diff --git a/.vite/deps/_metadata.json b/.vite/deps/_metadata.json
new file mode 100644
index 0000000..bd627d5
--- /dev/null
+++ b/.vite/deps/_metadata.json
@@ -0,0 +1,8 @@
+{
+ "hash": "eef72e69",
+ "configHash": "23a093bf",
+ "lockfileHash": "e3b0c442",
+ "browserHash": "e8ef8295",
+ "optimized": {},
+ "chunks": {}
+}
\ No newline at end of file
diff --git a/.vite/deps_temp_89ecc3b4/package.json b/.vite/deps/package.json
similarity index 100%
rename from .vite/deps_temp_89ecc3b4/package.json
rename to .vite/deps/package.json
diff --git a/dist/base.js b/dist/base.js
index 54a45d9..6e4b123 100644
--- a/dist/base.js
+++ b/dist/base.js
@@ -1,5 +1,5 @@
(function(global, factory) {
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@apigo.cc/state"), require("@apigo.cc/bootstrap")) : typeof define === "function" && define.amd ? define(["exports", "@apigo.cc/state", "@apigo.cc/bootstrap"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ApigoBase = {}, global.ApigoState));
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@apigo.cc/state")) : typeof define === "function" && define.amd ? define(["exports", "@apigo.cc/state"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ApigoBase = global.ApigoBase || {}, global.ApigoState));
})(this, function(exports2, state) {
"use strict";
const HTTP = {
@@ -51,122 +51,11 @@
return response;
}
};
- const APIComponent = state.Component.register("API", (container) => {
- container.request = state.NewState({ url: "", method: "GET", headers: {}, data: null, timeout: 1e4, responseType: "" });
- container.response = state.NewState({ loading: false, ok: null, status: null, error: null, headers: {}, responseType: "", result: null });
- container.result = state.NewState();
- container.do = (opt = {}) => {
- return new Promise((resolve, reject) => {
- const req = { ...container.request, ...opt };
- if (!req.url) throw new Error(".url is required");
- req.headers = { ...container.request.headers, ...opt.headers };
- container.response.loading = true;
- HTTP.request(req).then((resp) => {
- Object.keys(resp).forEach((k) => {
- if (k !== "result") container.response[k] = resp[k];
- });
- if (resp.result && typeof resp.result === "object" && container.result && typeof container.result === "object") {
- Object.assign(container.result, resp.result);
- } else {
- container.result = resp.result;
- }
- container.response.loading = false;
- if (resp.ok === false) throw new Error(resp.error);
- if (typeof resp.result === "object" && resp.result.error) throw new Error(resp.result.error);
- container.dispatchEvent(new CustomEvent("response", { detail: resp, bubbles: false }));
- resolve(resp);
- }).catch((err) => {
- var _a;
- if (!opt.noui && ((_a = globalThis.UI) == null ? void 0 : _a.toast)) UI.toast(err.message, { type: "danger" });
- container.dispatchEvent(new CustomEvent("error", { detail: err, bubbles: true }));
- reject(err);
- });
- });
- };
- let _autoTimer = null;
- container.request.__watch(null, () => {
- if (!container.hasAttribute("auto") || !container.request.url) return;
- if (_autoTimer) return;
- _autoTimer = Promise.resolve().then(() => {
- container.do();
- _autoTimer = null;
- });
- });
- });
- const UI$1 = {};
- state.Component.register("Modal", (container) => {
- container.modal = new bootstrap.Modal(container);
- container.addEventListener("bind", (e) => {
- e.detail ? container.modal.show() : container.modal.hide();
- });
- container.addEventListener("hide.bs.modal", () => {
- var _a;
- (_a = document.activeElement) == null ? void 0 : _a.blur();
- container.dispatchEvent(new CustomEvent("change", { bubbles: false, detail: false }));
- });
- state.Util.copyFunction(container, container.modal, "show", "hide");
- }, state.Util.makeDom(
- /*html*/
- `
-
-`
- ));
- state.Component.register("Dialog", state.Component.getSetupFunction("Modal"), state.Util.makeDom(
- /*html*/
- `
-
-`
- ));
- let _dialogCount = 0;
- UI$1.showDialog = function({ title = "", message = "", buttons = ["{#Close#}"], type = "body" }) {
- const d = document.body.appendChild(document.createElement("Dialog"));
- d.style.zIndex = 2e3 + ++_dialogCount;
- Promise.resolve().then(() => {
- Object.assign(d.state, { message, title, type, buttons });
- d.show();
- });
- return new Promise((resolve) => {
- d.addEventListener("change", (e) => {
- _dialogCount--;
- resolve(d.result || 0);
- d.remove();
- });
- });
- };
- UI$1.alert = function(message, options = {}) {
- return UI$1.showDialog({ message, ...options });
- };
- UI$1.confirm = function(message, options = {}) {
- return new Promise((resolve) => UI$1.showDialog({ message, buttons: ["{#Cancel#}", "{#Confirm#}"], ...options }).then((index2) => resolve(index2 >= 2)).catch(() => resolve(false)));
- };
- state.Component.register("Toast", (container) => {
+ globalThis.HTTP = HTTP;
+ const UI = {};
+ globalThis.Component.register("Toast", (container) => {
container.toast = new bootstrap.Toast(container, { autohide: container.state.delay > 0 });
- state.Util.copyFunction(container, container.toast, "show", "hide");
+ globalThis.Util.copyFunction(container, container.toast, "show", "hide");
container.addEventListener("show.bs.toast", () => {
if (container.state.delay > 0) {
let timer;
@@ -184,7 +73,7 @@
container.addEventListener("mouseleave", startTimer);
}
});
- }, state.Util.makeDom(
+ }, globalThis.Util.makeDom(
/*html*/
`
@@ -206,21 +95,22 @@
`
- ), state.Util.makeDom(
+ ), globalThis.Util.makeDom(
/*html*/
``
));
- UI$1.toast = function(message, options = {}) {
+ UI.toast = function(message, options = {}) {
const delay = options.delay ?? 5e3;
const t = document.createElement("Toast");
t.state = { delay, left: delay ? delay / 1e3 : void 0, type: options.type || "primary", message, buttons: options.buttons || [] };
- state.$(`[toast-container="${options.container || "default"}"]`).appendChild(t);
+ globalThis.$(`[toast-container="${options.container || "default"}"]`).appendChild(t);
Promise.resolve().then(() => t.show());
};
- UI$1.toastConfirm = function(message, options = {}) {
- return new Promise((resolve) => UI$1.toast(message, { buttons: ["{#Confirm#}"], ...options }).then((index2) => resolve(index2 === 1)).catch(() => resolve(false)));
+ UI.toastConfirm = function(message, options = {}) {
+ return new Promise((resolve) => UI.toast(message, { buttons: ["{#Confirm#}"], ...options }).then((index2) => resolve(index2 === 1)).catch(() => resolve(false)));
};
- const AUTOFORM_BLUEPRINT = state.Util.makeDom(
+ globalThis.UI = UI;
+ const AUTOFORM_BLUEPRINT = globalThis.Util.makeDom(
/*html*/
`
@@ -261,29 +151,29 @@
`
);
- const AUTOFORM_STYLE = state.Util.makeDom(
+ const AUTOFORM_STYLE = globalThis.Util.makeDom(
/*html*/
``
);
- state.Component.register("AutoForm", (container) => {
+ globalThis.Component.register("AutoForm", (container) => {
if (!container.state.schema) container.state.schema = [];
- const ensureProxy = (v) => v && typeof v === "object" && !v.__isProxy ? state.NewState(v) : v;
+ const ensureProxy = (v) => v && typeof v === "object" && !v.__isProxy ? globalThis.NewState(v) : v;
container.state.__watch("data", (v) => container.data = ensureProxy(v));
container.data = ensureProxy(container.state.data || {});
container.vertical = container.hasAttribute("vertical");
@@ -293,7 +183,7 @@
container.request = { method: "POST" };
container.response = {};
container.result = null;
- container.form = state.$(container, "form");
+ container.form = globalThis.$(container, "form");
container.submit = (opt = {}) => {
var _a, _b;
if (!container.form.reportValidity()) return (_b = (_a = globalThis.UI) == null ? void 0 : _a.toast) == null ? void 0 : _b.call(_a, "{#verify failed#}", { type: "danger" });
@@ -301,7 +191,7 @@
const req = { ...container.request, data: container.data, noui: true, ...opt };
let task = null;
if (container.api) task = container.api.do(req);
- else if (container.request.url) task = HTTP.request(req);
+ else if (container.request.url) task = globalThis.HTTP.request(req);
else return console.warn("{#please config .api or .request.url to auto submit#}");
task.then((resp) => {
container.response = resp;
@@ -310,7 +200,7 @@
container.dispatchEvent(new CustomEvent("response", { detail: resp, bubbles: false }));
}).catch((err) => {
var _a2;
- if ((_a2 = globalThis.UI) == null ? void 0 : _a2.toast) UI.toast(err.message, { type: "danger" });
+ if ((_a2 = globalThis.UI) == null ? void 0 : _a2.toast) globalThis.UI.toast(err.message, { type: "danger" });
container.dispatchEvent(new CustomEvent("error", { detail: err, bubbles: true }));
});
};
@@ -345,215 +235,17 @@
_addAutoFormComponent: (name, type) => {
const wrapper = findAnchorInBlueprint(AUTOFORM_BLUEPRINT);
if (wrapper) {
- const node = state.Util.makeDom(`<${name} $if="item.type?.toLowerCase() === '${type.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="this.data[item.name]" class="w-100">${name}>`);
+ const node = globalThis.Util.makeDom(`<${name} $if="item.type?.toLowerCase() === '${type.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="this.data[item.name]" class="w-100">${name}>`);
wrapper.appendChild(node);
}
}
};
- state.Component.register("TagsInput", (container) => {
- container._thisObj = container;
- container.addEventListener("bind", (e) => {
- container.state.tags = Array.isArray(e.detail) ? e.detail : [];
- });
- }, state.Util.makeDom(
- /*html*/
- `
-
-
-
-
-
-
-`
- ), state.Util.makeDom(
- /*html*/
- ``
- ));
- AutoForm.register("TagsInput");
- state.Component.register("DatePicker", (container) => {
- container._thisObj = container;
- container.state = state.NewState({ start: "", end: "" });
- container.addEventListener("bind", (e) => {
- var _a, _b, _c;
- container.state.start = e.detail || "";
- const form = container.closest("AutoForm");
- const name = container.getAttribute("name");
- const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
- const rangeEnd = ((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd;
- if (form && rangeEnd) {
- container.state.end = form.data[rangeEnd] || "";
- }
- });
- Object.defineProperty(container, "isRange", {
- get: () => {
- var _a, _b, _c;
- const form = container.closest("AutoForm");
- const name = container.getAttribute("name");
- const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
- return !!(((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd);
- }
- });
- Object.defineProperty(container, "value", {
- get: () => container.state.start,
- set: (v) => {
- container.state.start = v || "";
- }
- });
- container.updateStart = (val) => {
- container.state.start = val;
- container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: val }));
- };
- container.updateEnd = (val) => {
- var _a, _b, _c;
- container.state.end = val;
- const form = container.closest("AutoForm");
- const name = container.getAttribute("name");
- const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
- const rangeEnd = ((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd;
- if (form && rangeEnd) {
- form.data[rangeEnd] = val;
- }
- };
- }, state.Util.makeDom(
- /*html*/
- `
-
-
-
- -
-
-
-
-`
- ));
- state.Component.register("ColorPicker", (container) => {
- container._thisObj = container;
- container.state = state.NewState({ value: "#000000" });
- container.addEventListener("bind", (e) => {
- container.state.value = e.detail || "#000000";
- });
- Object.defineProperty(container, "value", {
- get: () => container.state.value,
- set: (v) => {
- container.state.value = v || "#000000";
- }
- });
- container.updateValue = (val) => {
- container.state.value = val;
- container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: val }));
- };
- }, state.Util.makeDom(
- /*html*/
- `
-
-
-
-
-`
- ));
- const BOOTSTRAP_ICONS = ["alarm", "archive", "arrow-left", "arrow-right", "bag", "bank", "basket", "bell", "bookmark", "box", "briefcase", "calendar", "camera", "cart", "chat", "check", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "clock", "cloud", "code", "collection", "command", "cpu", "credit-card", "cup", "dash", "database", "display", "door-closed", "download", "droplet", "earbuds", "edit", "egg", "eject", "envelope", "eraser", "eye", "file", "filter", "flag", "folder", "gear", "gem", "gift", "graph-up", "grid", "hammer", "hand-thumbs-up", "heart", "house", "image", "inbox", "info-circle", "journal", "key", "laptop", "layers", "layout-text-sidebar-reverse", "lightbulb", "link", "list", "lock", "map", "mic", "moon", "mouse", "music-note", "newspaper", "palette", "paperclip", "pause", "pencil", "person", "phone", "pie-chart", "play", "plus", "printer", "puzzle", "question-circle", "reception-4", "record", "reply", "rss", "save", "search", "send", "server", "share", "shield", "shop", "shuffle", "skip-end", "skip-start", "slash", "sliders", "smartphone", "speaker", "speedometer", "spellcheck", "square", "star", "stickies", "stop", "stopwatch", "suit-heart", "sun", "table", "tag", "tags", "telephone", "terminal", "text-paragraph", "thermometer", "three-dots", "ticket", "tools", "trash", "trophy", "truck", "tv", "umbrella", "unlock", "upload", "vector-pen", "wallet", "watch", "wifi", "window", "wrench", "x", "zoom-in", "zoom-out", "activity", "at", "award", "backspace", "badge-3d", "badge-4k", "badge-8k", "badge-ad", "badge-ar", "badge-cc", "badge-hd", "badge-tm", "badge-vo", "badge-vr", "badge-wc", "bar-chart", "battery", "bicycle", "binoculars", "blockquote-left", "blockquote-right", "book", "bookshelf", "bootstrap", "border-all", "border-bottom", "border-center", "border-inner", "border-left", "border-middle", "border-outer", "border-right", "border-style", "border-top", "border-width", "bounding-box", "box-arrow-down", "box-arrow-in-down", "box-arrow-in-left", "box-arrow-in-right", "box-arrow-in-up", "box-arrow-left", "box-arrow-right", "box-arrow-up", "box-seam", "brightness-alt-high", "brightness-alt-low", "brightness-high", "brightness-low", "broadcast", "brush", "bucket", "bug", "building", "bullseye", "calculator", "calendar-check", "calendar-date", "calendar-day", "calendar-event", "calendar-minus", "calendar-month", "calendar-plus", "calendar-range", "calendar-week", "calendar-x", "calendar2", "calendar3", "calendar4", "camera-reels", "camera-video", "capslock", "card-checklist", "card-heading", "card-image", "card-list", "card-text", "caret-down", "caret-left", "caret-right", "caret-up", "cart-check", "cart-dash", "cart-plus", "cart-x", "cash", "cash-stack", "cast", "chat-dots", "chat-left", "chat-quote", "chat-right", "chat-square", "chat-text", "check-all", "check-circle", "check-square", "circle", "clipboard", "cloud-arrow-down", "cloud-arrow-up", "cloud-check", "cloud-download", "cloud-fog", "cloud-hail", "cloud-lightning", "cloud-minus", "cloud-moon", "cloud-plus", "cloud-rain", "cloud-slash", "cloud-snow", "cloud-sun", "cloud-upload", "clouds", "cloudy", "code-slash", "code-square", "collection-play", "columns", "columns-gap", "compass", "cone", "cone-striped", "controller", "credit-card-2-back", "credit-card-2-front", "crop", "cup-straw", "cursor", "dash-circle", "dash-square", "diagram-2", "diagram-3", "diamond", "dice-1", "dice-2", "dice-3", "dice-4", "dice-5", "dice-6", "disc", "discord", "distribute-horizontal", "distribute-vertical", "door-open", "dot", "droplet-half", "easel", "egg-fried", "emoji-angry", "emoji-dizzy", "emoji-expressionless", "emoji-frown", "emoji-heart-eyes", "emoji-laughing", "emoji-neutral", "emoji-smile", "emoji-sunglasses", "emoji-wink", "envelope-open", "exclamation", "exclamation-circle", "exclamation-diamond", "exclamation-octagon", "exclamation-square", "exclamation-triangle", "eye-slash", "eyedropper", "facebook", "file-arrow-down", "file-arrow-up", "file-binary", "file-break", "file-check", "file-code", "file-diff", "file-earmark", "file-excel", "file-image", "file-lock", "file-medical", "file-minus", "file-music", "file-pdf", "file-person", "file-play", "file-plus", "file-post", "file-ppt", "file-richtext", "file-slides", "file-spreadsheet", "file-text", "file-word", "file-zip", "files", "film", "filter-circle", "filter-left", "filter-right", "filter-square", "fingerprint", "flower1", "flower2", "flower3", "folder-check", "folder-minus", "folder-plus", "folder-symlink", "folder-x", "folder2-open", "fonts", "forward", "front", "fullscreen", "fullscreen-exit", "funnel", "gear-wide", "gender-female", "gender-male", "gender-trans", "geo", "geo-alt", "github", "globe", "google", "graph-down", "grid-1x2", "grid-3x2", "grid-3x3", "grip-horizontal", "grip-vertical", "hand-index", "hand-thumbs-down", "handbag", "hash", "headphones", "headset", "heart-half", "heptagon", "hourglass", "hourglass-bottom", "hourglass-split", "hourglass-top", "house-door", "hr", "hurricane", "image-alt", "images", "infinity", "input-cursor", "instagram", "intersect", "journal-album", "journal-arrow-down", "journal-arrow-up", "journal-bookmark", "journal-check", "journal-code", "journal-medical", "journal-minus", "journal-plus", "journal-richtext", "journal-text", "journal-x", "journals", "justify", "kanban", "keyboard", "ladder", "lamp", "layers-half", "layout-sidebar", "layout-split", "layout-three-columns", "life-preserver", "lightbulb-off", "lightning", "lightning-charge", "link-45deg", "linkedin", "list-check", "list-nested", "list-ol", "list-stars", "list-task", "list-ul", "mailbox", "markdown", "mask", "mastodon", "megaphone", "menu-app", "menu-button", "messenger", "mic-mute", "minecart", "minecart-loaded", "moisture", "mouse2", "mouse3", "music-note-beamed", "music-note-list", "music-player", "node-minus", "node-plus", "nut", "octagon", "option", "outlet", "paint-bucket", "patch-check", "patch-exclamation", "patch-minus", "patch-plus", "patch-question", "pause-btn", "pause-circle", "peace", "pen", "pencil-square", "pentagon", "person-badge", "person-bounding-box", "person-circle", "person-lines-fill", "phone-landscape", "phone-vibrate", "pie-chart-fill", "pin", "pin-angle", "pin-fill", "pin-map", "pip", "play-btn", "play-circle", "plug", "plus-circle", "plus-square", "power", "question", "question-diamond", "question-square", "rainbow", "receipt", "receipt-cutoff", "reception-0", "reception-1", "reception-2", "reception-3", "record-btn", "record-circle", "record2", "recycle", "reddit", "reply-all", "router", "rulers", "safe", "save2", "sd-card", "segmented-nav", "shield-check", "shield-exclamation", "shield-lock", "shield-shaded", "shield-slash", "shift", "signpost", "signpost-2", "signpost-split", "sim", "skip-backward", "skip-forward", "slack", "slash-circle", "slash-square", "smartwatch", "snow", "snow2", "snow3", "sort-alpha-down", "sort-alpha-up", "sort-numeric-down", "sort-numeric-up", "soundwave", "speedometer2", "square-half", "stack", "star-half", "stars", "stop-btn", "stop-circle", "suit-club", "suit-diamond", "suit-spade", "sunglasses", "sunrise", "sunset", "symmetry-horizontal", "symmetry-vertical", "tablet", "tablet-landscape", "telegram", "telephone-forward", "telephone-inbound", "telephone-outbound", "telephone-plus", "telephone-x", "text-center", "text-indent-left", "text-indent-right", "text-left", "text-right", "thermometer-half", "thermometer-high", "thermometer-low", "thermometer-snow", "thermometer-sun", "three-dots-vertical", "toggle-off", "toggle-on", "toggle2-off", "toggle2-on", "tornado", "translate", "trash2", "tree", "truck-flatbed", "tsunami", "type", "type-bold", "type-h1", "type-h2", "type-h3", "type-italic", "type-strikethrough", "type-underline", "ui-checks", "ui-checks-grid", "ui-radios", "ui-radios-grid", "union", "upc", "upc-scan", "view-list", "view-stacked", "vinyl", "voicemail", "volume-down", "volume-mute", "volume-off", "volume-up", "vr", "wallet2", "water", "whatsapp", "wifi-1", "wifi-2", "wifi-off", "wind", "window-dock", "window-sidebar", "x-circle", "x-diamond", "x-octagon", "x-square", "youtube"];
- state.Component.register("IconPicker", (container) => {
- container._thisObj = container;
- container.state = state.NewState({ value: "", search: "", open: false });
- container.addEventListener("bind", (e) => {
- container.state.value = e.detail || "";
- });
- Object.defineProperty(container, "value", {
- get: () => container.state.value,
- set: (v) => {
- container.state.value = v || "";
- }
- });
- Object.defineProperty(container, "filteredIcons", {
- get: () => {
- var _a;
- const s = ((_a = container.state.search) == null ? void 0 : _a.toLowerCase()) || "";
- return BOOTSTRAP_ICONS.filter((i) => i.includes(s));
- }
- });
- container.selectIcon = (icon) => {
- container.state.value = icon;
- container.state.open = false;
- container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: icon }));
- };
- container.toggle = () => {
- container.state.open = !container.state.open;
- if (container.state.open) {
- setTimeout(() => {
- var _a;
- (_a = state.$(container, "input")) == null ? void 0 : _a.focus();
- }, 10);
- }
- };
- const onGlobalClick = (e) => {
- if (!container.contains(e.target)) {
- container.state.open = false;
- }
- };
- window.addEventListener("click", onGlobalClick);
- container.addEventListener("remove", () => window.removeEventListener("click", onGlobalClick));
- }, state.Util.makeDom(
- /*html*/
- `
-
-
-
-
-
-
-
-
-
No icons found
-
-
-
-`
- ), state.Util.makeDom(
- /*html*/
- ``
- ));
- AutoForm.register("DatePicker");
- AutoForm.register("ColorPicker");
- AutoForm.register("IconPicker");
+ globalThis.AutoForm = AutoForm;
const VirtualScroll = (options = {}) => {
const itemHeights = /* @__PURE__ */ new Map();
const groupHeights = /* @__PURE__ */ new Map();
let groupItemCount = 1;
- const avg = state.Util.newAvg();
+ const avg = globalThis.Util.newAvg();
let padTop = 0, rowGap = 0, topMargin = 0, itemMarginTop = null, itemMarginBottom = null, listInited = false;
const providedItemHeight = options.itemHeight || null;
return {
@@ -657,7 +349,355 @@
}
};
};
- state.Component.register("List", (container) => {
+ globalThis.VirtualScroll = VirtualScroll;
+ let _mouseMoverMoving = false;
+ let _mouseMoverPos = {};
+ let _mouseMoverEvents = {};
+ const MouseMover = {
+ start: (event, { onmousemove, onmouseup }) => {
+ _mouseMoverPos = { x: event.clientX, y: event.clientY, w: 0, h: 0 };
+ _mouseMoverEvents = { onmousemove, onmouseup };
+ _mouseMoverMoving = true;
+ }
+ };
+ if (typeof document !== "undefined") {
+ document.addEventListener("mouseup", (event) => {
+ var _a;
+ if (!_mouseMoverMoving) return;
+ _mouseMoverMoving = false;
+ (_a = _mouseMoverEvents.onmouseup) == null ? void 0 : _a.call(_mouseMoverEvents, { event, ..._mouseMoverPos });
+ });
+ document.addEventListener("mousemove", (event) => {
+ var _a;
+ if (!_mouseMoverMoving) return;
+ _mouseMoverPos.w = event.clientX - _mouseMoverPos.x;
+ _mouseMoverPos.h = event.clientY - _mouseMoverPos.y;
+ (_a = _mouseMoverEvents.onmousemove) == null ? void 0 : _a.call(_mouseMoverEvents, { event, ..._mouseMoverPos });
+ });
+ }
+ globalThis.MouseMover = MouseMover;
+ const APIComponent = globalThis.Component.register("API", (container) => {
+ container.request = globalThis.NewState({ url: "", method: "GET", headers: {}, data: null, timeout: 1e4, responseType: "" });
+ container.response = globalThis.NewState({ loading: false, ok: null, status: null, error: null, headers: {}, responseType: "", result: null });
+ container.result = globalThis.NewState();
+ container.do = (opt = {}) => {
+ return new Promise((resolve, reject) => {
+ const req = { ...container.request, ...opt };
+ if (!req.url) throw new Error(".url is required");
+ req.headers = { ...container.request.headers, ...opt.headers };
+ container.response.loading = true;
+ globalThis.HTTP.request(req).then((resp) => {
+ Object.keys(resp).forEach((k) => {
+ if (k !== "result") container.response[k] = resp[k];
+ });
+ if (resp.result && typeof resp.result === "object" && container.result && typeof container.result === "object") {
+ Object.assign(container.result, resp.result);
+ } else {
+ container.result = resp.result;
+ }
+ container.response.loading = false;
+ if (resp.ok === false) throw new Error(resp.error);
+ if (typeof resp.result === "object" && resp.result.error) throw new Error(resp.result.error);
+ container.dispatchEvent(new CustomEvent("response", { detail: resp, bubbles: false }));
+ resolve(resp);
+ }).catch((err) => {
+ var _a;
+ if (!opt.noui && ((_a = globalThis.UI) == null ? void 0 : _a.toast)) globalThis.UI.toast(err.message, { type: "danger" });
+ container.dispatchEvent(new CustomEvent("error", { detail: err, bubbles: true }));
+ reject(err);
+ });
+ });
+ };
+ let _autoTimer = null;
+ container.request.__watch(null, () => {
+ if (!container.hasAttribute("auto") || !container.request.url) return;
+ if (_autoTimer) return;
+ _autoTimer = Promise.resolve().then(() => {
+ container.do();
+ _autoTimer = null;
+ });
+ });
+ });
+ globalThis.Component.register("Modal", (container) => {
+ container.modal = new bootstrap.Modal(container);
+ container.addEventListener("bind", (e) => {
+ e.detail ? container.modal.show() : container.modal.hide();
+ });
+ container.addEventListener("hide.bs.modal", () => {
+ var _a;
+ (_a = document.activeElement) == null ? void 0 : _a.blur();
+ container.dispatchEvent(new CustomEvent("change", { bubbles: false, detail: false }));
+ });
+ globalThis.Util.copyFunction(container, container.modal, "show", "hide");
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+`
+ ));
+ globalThis.Component.register("Dialog", globalThis.Component.getSetupFunction("Modal"), globalThis.Util.makeDom(
+ /*html*/
+ `
+
+`
+ ));
+ let _dialogCount = 0;
+ globalThis.UI.showDialog = function({ title = "", message = "", buttons = ["{#Close#}"], type = "body" }) {
+ const d = document.body.appendChild(document.createElement("Dialog"));
+ d.style.zIndex = 2e3 + ++_dialogCount;
+ Promise.resolve().then(() => {
+ Object.assign(d.state, { message, title, type, buttons });
+ d.show();
+ });
+ return new Promise((resolve) => {
+ d.addEventListener("change", (e) => {
+ _dialogCount--;
+ resolve(d.result || 0);
+ d.remove();
+ });
+ });
+ };
+ globalThis.UI.alert = function(message, options = {}) {
+ return globalThis.UI.showDialog({ message, ...options });
+ };
+ globalThis.UI.confirm = function(message, options = {}) {
+ return new Promise((resolve) => globalThis.UI.showDialog({ message, buttons: ["{#Cancel#}", "{#Confirm#}"], ...options }).then((index2) => resolve(index2 >= 2)).catch(() => resolve(false)));
+ };
+ globalThis.Component.register("TagsInput", (container) => {
+ container._thisObj = container;
+ container.addEventListener("bind", (e) => {
+ container.state.tags = Array.isArray(e.detail) ? e.detail : [];
+ });
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+
+
+
+
+
+`
+ ), globalThis.Util.makeDom(
+ /*html*/
+ ``
+ ));
+ if (globalThis.AutoForm) {
+ globalThis.AutoForm.register("TagsInput");
+ }
+ globalThis.Component.register("DatePicker", (container) => {
+ container._thisObj = container;
+ container.state = globalThis.NewState({ start: "", end: "" });
+ container.addEventListener("bind", (e) => {
+ var _a, _b, _c;
+ container.state.start = e.detail || "";
+ const form = container.closest("AutoForm");
+ const name = container.getAttribute("name");
+ const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
+ const rangeEnd = ((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd;
+ if (form && rangeEnd) {
+ container.state.end = form.data[rangeEnd] || "";
+ }
+ });
+ Object.defineProperty(container, "isRange", {
+ get: () => {
+ var _a, _b, _c;
+ const form = container.closest("AutoForm");
+ const name = container.getAttribute("name");
+ const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
+ return !!(((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd);
+ }
+ });
+ Object.defineProperty(container, "value", {
+ get: () => container.state.start,
+ set: (v) => {
+ container.state.start = v || "";
+ }
+ });
+ container.updateStart = (val) => {
+ container.state.start = val;
+ container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: val }));
+ };
+ container.updateEnd = (val) => {
+ var _a, _b, _c;
+ container.state.end = val;
+ const form = container.closest("AutoForm");
+ const name = container.getAttribute("name");
+ const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
+ const rangeEnd = ((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd;
+ if (form && rangeEnd) {
+ form.data[rangeEnd] = val;
+ }
+ };
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+
+
+ -
+
+
+
+`
+ ));
+ if (globalThis.AutoForm) {
+ globalThis.AutoForm.register("DatePicker");
+ }
+ globalThis.Component.register("ColorPicker", (container) => {
+ container._thisObj = container;
+ container.state = globalThis.NewState({ value: "#000000" });
+ container.addEventListener("bind", (e) => {
+ container.state.value = e.detail || "#000000";
+ });
+ Object.defineProperty(container, "value", {
+ get: () => container.state.value,
+ set: (v) => {
+ container.state.value = v || "#000000";
+ }
+ });
+ container.updateValue = (val) => {
+ container.state.value = val;
+ container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: val }));
+ };
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+
+
+
+`
+ ));
+ if (globalThis.AutoForm) {
+ globalThis.AutoForm.register("ColorPicker");
+ }
+ const BOOTSTRAP_ICONS = ["alarm", "archive", "arrow-left", "arrow-right", "bag", "bank", "basket", "bell", "bookmark", "box", "briefcase", "calendar", "camera", "cart", "chat", "check", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "clock", "cloud", "code", "collection", "command", "cpu", "credit-card", "cup", "dash", "database", "display", "door-closed", "download", "droplet", "earbuds", "edit", "egg", "eject", "envelope", "eraser", "eye", "file", "filter", "flag", "folder", "gear", "gem", "gift", "graph-up", "grid", "hammer", "hand-thumbs-up", "heart", "house", "image", "inbox", "info-circle", "journal", "key", "laptop", "layers", "layout-text-sidebar-reverse", "lightbulb", "link", "list", "lock", "map", "mic", "moon", "mouse", "music-note", "newspaper", "palette", "paperclip", "pause", "pencil", "person", "phone", "pie-chart", "play", "plus", "printer", "puzzle", "question-circle", "reception-4", "record", "reply", "rss", "save", "search", "send", "server", "share", "shield", "shop", "shuffle", "skip-end", "skip-start", "slash", "sliders", "smartphone", "speaker", "speedometer", "spellcheck", "square", "star", "stickies", "stop", "stopwatch", "suit-heart", "sun", "table", "tag", "tags", "telephone", "terminal", "text-paragraph", "thermometer", "three-dots", "ticket", "tools", "trash", "trophy", "truck", "tv", "umbrella", "unlock", "upload", "vector-pen", "wallet", "watch", "wifi", "window", "wrench", "x", "zoom-in", "zoom-out", "activity", "at", "award", "backspace", "badge-3d", "badge-4k", "badge-8k", "badge-ad", "badge-ar", "badge-cc", "badge-hd", "badge-tm", "badge-vo", "badge-vr", "badge-wc", "bar-chart", "battery", "bicycle", "binoculars", "blockquote-left", "blockquote-right", "book", "bookshelf", "bootstrap", "border-all", "border-bottom", "border-center", "border-inner", "border-left", "border-middle", "border-outer", "border-right", "border-style", "border-top", "border-width", "bounding-box", "box-arrow-down", "box-arrow-in-down", "box-arrow-in-left", "box-arrow-in-right", "box-arrow-in-up", "box-arrow-left", "box-arrow-right", "box-arrow-up", "box-seam", "brightness-alt-high", "brightness-alt-low", "brightness-high", "brightness-low", "broadcast", "brush", "bucket", "bug", "building", "bullseye", "calculator", "calendar-check", "calendar-date", "calendar-day", "calendar-event", "calendar-minus", "calendar-month", "calendar-plus", "calendar-range", "calendar-week", "calendar-x", "calendar2", "calendar3", "calendar4", "camera-reels", "camera-video", "capslock", "card-checklist", "card-heading", "card-image", "card-list", "card-text", "caret-down", "caret-left", "caret-right", "caret-up", "cart-check", "cart-dash", "cart-plus", "cart-x", "cash", "cash-stack", "cast", "chat-dots", "chat-left", "chat-quote", "chat-right", "chat-square", "chat-text", "check-all", "check-circle", "check-square", "circle", "clipboard", "cloud-arrow-down", "cloud-arrow-up", "cloud-check", "cloud-download", "cloud-fog", "cloud-hail", "cloud-lightning", "cloud-minus", "cloud-moon", "cloud-plus", "cloud-rain", "cloud-slash", "cloud-snow", "cloud-sun", "cloud-upload", "clouds", "cloudy", "code-slash", "code-square", "collection-play", "columns", "columns-gap", "compass", "cone", "cone-striped", "controller", "credit-card-2-back", "credit-card-2-front", "crop", "cup-straw", "cursor", "dash-circle", "dash-square", "diagram-2", "diagram-3", "diamond", "dice-1", "dice-2", "dice-3", "dice-4", "dice-5", "dice-6", "disc", "discord", "distribute-horizontal", "distribute-vertical", "door-open", "dot", "droplet-half", "easel", "egg-fried", "emoji-angry", "emoji-dizzy", "emoji-expressionless", "emoji-frown", "emoji-heart-eyes", "emoji-laughing", "emoji-neutral", "emoji-smile", "emoji-sunglasses", "emoji-wink", "envelope-open", "exclamation", "exclamation-circle", "exclamation-diamond", "exclamation-octagon", "exclamation-square", "exclamation-triangle", "eye-slash", "eyedropper", "facebook", "file-arrow-down", "file-arrow-up", "file-binary", "file-break", "file-check", "file-code", "file-diff", "file-earmark", "file-excel", "file-image", "file-lock", "file-medical", "file-minus", "file-music", "file-pdf", "file-person", "file-play", "file-plus", "file-post", "file-ppt", "file-richtext", "file-slides", "file-spreadsheet", "file-text", "file-word", "file-zip", "files", "film", "filter-circle", "filter-left", "filter-right", "filter-square", "fingerprint", "flower1", "flower2", "flower3", "folder-check", "folder-minus", "folder-plus", "folder-symlink", "folder-x", "folder2-open", "fonts", "forward", "front", "fullscreen", "fullscreen-exit", "funnel", "gear-wide", "gender-female", "gender-male", "gender-trans", "geo", "geo-alt", "github", "globe", "google", "graph-down", "grid-1x2", "grid-3x2", "grid-3x3", "grip-horizontal", "grip-vertical", "hand-index", "hand-thumbs-down", "handbag", "hash", "headphones", "headset", "heart-half", "heptagon", "hourglass", "hourglass-bottom", "hourglass-split", "hourglass-top", "house-door", "hr", "hurricane", "image-alt", "images", "infinity", "input-cursor", "instagram", "intersect", "journal-album", "journal-arrow-down", "journal-arrow-up", "journal-bookmark", "journal-check", "journal-code", "journal-medical", "journal-minus", "journal-plus", "journal-richtext", "journal-text", "journal-x", "journals", "justify", "kanban", "keyboard", "ladder", "lamp", "layers-half", "layout-sidebar", "layout-split", "layout-three-columns", "life-preserver", "lightbulb-off", "lightning", "lightning-charge", "link-45deg", "linkedin", "list-check", "list-nested", "list-ol", "list-stars", "list-task", "list-ul", "mailbox", "markdown", "mask", "mastodon", "megaphone", "menu-app", "menu-button", "messenger", "mic-mute", "minecart", "minecart-loaded", "moisture", "mouse2", "mouse3", "music-note-beamed", "music-note-list", "music-player", "node-minus", "node-plus", "nut", "octagon", "option", "outlet", "paint-bucket", "patch-check", "patch-exclamation", "patch-minus", "patch-plus", "patch-question", "pause-btn", "pause-circle", "peace", "pen", "pencil-square", "pentagon", "person-badge", "person-bounding-box", "person-circle", "person-lines-fill", "phone-landscape", "phone-vibrate", "pie-chart-fill", "pin", "pin-angle", "pin-fill", "pin-map", "pip", "play-btn", "play-circle", "plug", "plus-circle", "plus-square", "power", "question", "question-diamond", "question-square", "rainbow", "receipt", "receipt-cutoff", "reception-0", "reception-1", "reception-2", "reception-3", "record-btn", "record-circle", "record2", "recycle", "reddit", "reply-all", "router", "rulers", "safe", "save2", "sd-card", "segmented-nav", "shield-check", "shield-exclamation", "shield-lock", "shield-shaded", "shield-slash", "shift", "signpost", "signpost-2", "signpost-split", "sim", "skip-backward", "skip-forward", "slack", "slash-circle", "slash-square", "smartwatch", "snow", "snow2", "snow3", "sort-alpha-down", "sort-alpha-up", "sort-numeric-down", "sort-numeric-up", "soundwave", "speedometer2", "square-half", "stack", "star-half", "stars", "stop-btn", "stop-circle", "suit-club", "suit-diamond", "suit-spade", "sunglasses", "sunrise", "sunset", "symmetry-horizontal", "symmetry-vertical", "tablet", "tablet-landscape", "telegram", "telephone-forward", "telephone-inbound", "telephone-outbound", "telephone-plus", "telephone-x", "text-center", "text-indent-left", "text-indent-right", "text-left", "text-right", "thermometer-half", "thermometer-high", "thermometer-low", "thermometer-snow", "thermometer-sun", "three-dots-vertical", "toggle-off", "toggle-on", "toggle2-off", "toggle2-on", "tornado", "translate", "trash2", "tree", "truck-flatbed", "tsunami", "type", "type-bold", "type-h1", "type-h2", "type-h3", "type-italic", "type-strikethrough", "type-underline", "ui-checks", "ui-checks-grid", "ui-radios", "ui-radios-grid", "union", "upc", "upc-scan", "view-list", "view-stacked", "vinyl", "voicemail", "volume-down", "volume-mute", "volume-off", "volume-up", "vr", "wallet2", "water", "whatsapp", "wifi-1", "wifi-2", "wifi-off", "wind", "window-dock", "window-sidebar", "x-circle", "x-diamond", "x-octagon", "x-square", "youtube"];
+ globalThis.Component.register("IconPicker", (container) => {
+ container._thisObj = container;
+ container.state = globalThis.NewState({ value: "", search: "", open: false });
+ container.addEventListener("bind", (e) => {
+ container.state.value = e.detail || "";
+ });
+ Object.defineProperty(container, "value", {
+ get: () => container.state.value,
+ set: (v) => {
+ container.state.value = v || "";
+ }
+ });
+ Object.defineProperty(container, "filteredIcons", {
+ get: () => {
+ var _a;
+ const s = ((_a = container.state.search) == null ? void 0 : _a.toLowerCase()) || "";
+ return BOOTSTRAP_ICONS.filter((i) => i.includes(s));
+ }
+ });
+ container.selectIcon = (icon) => {
+ container.state.value = icon;
+ container.state.open = false;
+ container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: icon }));
+ };
+ container.toggle = () => {
+ container.state.open = !container.state.open;
+ if (container.state.open) {
+ setTimeout(() => {
+ var _a;
+ (_a = globalThis.$(container, "input")) == null ? void 0 : _a.focus();
+ }, 10);
+ }
+ };
+ const onGlobalClick = (e) => {
+ if (!container.contains(e.target)) {
+ container.state.open = false;
+ }
+ };
+ window.addEventListener("click", onGlobalClick);
+ container.addEventListener("remove", () => window.removeEventListener("click", onGlobalClick));
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+
+
+
+
+
+
+
+
No icons found
+
+
+
+`
+ ), globalThis.Util.makeDom(
+ /*html*/
+ ``
+ ));
+ if (globalThis.AutoForm) {
+ globalThis.AutoForm.register("IconPicker");
+ }
+ globalThis.Component.register("List", (container) => {
container.mode = container.getAttribute("mode") || "normal";
container.fast = container.hasAttribute("fast");
container.collapsible = container.hasAttribute("collapsible");
@@ -675,10 +715,10 @@
groupicon: "folder",
itemicon: "file"
};
- container.collapsed = state.NewState({});
+ container.collapsed = globalThis.NewState({});
container.state.renderedList = [];
const updateFlatList = () => {
- state.Util.updateDefaults(container, defaultSets);
+ globalThis.Util.updateDefaults(container, defaultSets);
const list = container.state.list || [], flatList = [];
if (container.mode === "group") {
const itemMap = {};
@@ -709,7 +749,7 @@
container.state.flatList = flatList;
};
container.state.__watch("list", updateFlatList);
- const vs = container.fast ? VirtualScroll() : null;
+ const vs = container.fast ? globalThis.VirtualScroll() : null;
let refreshing = false;
container.refresh = () => {
if (!container.fast || refreshing) return;
@@ -757,125 +797,100 @@
}
};
updateFlatList();
- }, state.Util.makeDom(
+ }, globalThis.Util.makeDom(
/*html*/
`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`
));
- state.Component.register("Nav", (container) => {
+ globalThis.Component.register("Nav", (container) => {
container.vertical = container.hasAttribute("vertical");
container.click = (item, noselect) => {
- if (!item.noselect && !noselect) state.Hash.nav = item.name;
+ if (!item.noselect && !noselect) globalThis.Hash.nav = item.name;
container.dispatchEvent(new CustomEvent("nav", { detail: { item }, bubbles: false }));
};
- }, state.Util.makeDom(
+ }, globalThis.Util.makeDom(
/*html*/
`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`
));
- let _mouseMoverMoving = false;
- let _mouseMoverPos = {};
- let _mouseMoverEvents = {};
- const MouseMover = {
- start: (event, { onmousemove, onmouseup }) => {
- _mouseMoverPos = { x: event.clientX, y: event.clientY, w: 0, h: 0 };
- _mouseMoverEvents = { onmousemove, onmouseup };
- _mouseMoverMoving = true;
- }
- };
- if (typeof document !== "undefined") {
- document.addEventListener("mouseup", (event) => {
- var _a;
- if (!_mouseMoverMoving) return;
- _mouseMoverMoving = false;
- (_a = _mouseMoverEvents.onmouseup) == null ? void 0 : _a.call(_mouseMoverEvents, { event, ..._mouseMoverPos });
- });
- document.addEventListener("mousemove", (event) => {
- var _a;
- if (!_mouseMoverMoving) return;
- _mouseMoverPos.w = event.clientX - _mouseMoverPos.x;
- _mouseMoverPos.h = event.clientY - _mouseMoverPos.y;
- (_a = _mouseMoverEvents.onmousemove) == null ? void 0 : _a.call(_mouseMoverEvents, { event, ..._mouseMoverPos });
- });
- }
- state.Component.register("Resizer", (container) => {
+ globalThis.Component.register("Resizer", (container) => {
container.isVertical = container.hasAttribute("vertical");
const min = parseInt(container.getAttribute("min")) || 10;
const max = parseInt(container.getAttribute("max")) || 1e3;
@@ -891,7 +906,7 @@
};
container.addEventListener("mousedown", (event) => {
const startSize = container.isVertical ? target.offsetHeight : target.offsetWidth;
- MouseMover.start(event, {
+ globalThis.MouseMover.start(event, {
onmousemove: ({ w, h }) => {
const newSize = getSize(startSize, w, h);
target.style[container.isVertical ? "height" : "width"] = newSize + "px";
@@ -904,38 +919,12 @@
}
});
});
- }, state.Util.makeDom(
+ }, globalThis.Util.makeDom(
/*html*/
`
`
));
- if (typeof window !== "undefined") {
- window.addEventListener("beforeunload", (event) => {
- if (state.State.exitBlocks > 0) event.preventDefault();
- });
- }
- const htmlNode = document.documentElement;
- if (!htmlNode.hasAttribute("$data-bs-theme") && !htmlNode.hasAttribute("data-bs-theme")) {
- htmlNode.setAttribute("$data-bs-theme", "LocalStorage.darkMode?'dark':'light'");
- }
- globalThis.HTTP = HTTP;
- globalThis.UI = UI$1;
- globalThis.AutoForm = AutoForm;
- globalThis.MouseMover = MouseMover;
- globalThis.VirtualScroll = VirtualScroll;
- const ApigoBase = {
- HTTP,
- UI: UI$1,
- AutoForm,
- MouseMover,
- VirtualScroll,
- State: state.State,
- List: VirtualScroll
- };
- if (typeof document !== "undefined") {
- globalThis.ApigoBase = ApigoBase;
- }
Object.defineProperty(exports2, "State", {
enumerable: true,
get: () => state.State
@@ -944,7 +933,7 @@
exports2.AutoForm = AutoForm;
exports2.HTTP = HTTP;
exports2.MouseMover = MouseMover;
- exports2.UI = UI$1;
+ exports2.UI = UI;
exports2.VirtualScroll = VirtualScroll;
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
});
diff --git a/dist/base.min.js b/dist/base.min.js
index 4cf9dd4..b52fd8a 100644
--- a/dist/base.min.js
+++ b/dist/base.min.js
@@ -1 +1 @@
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("@apigo.cc/state"),require("@apigo.cc/bootstrap")):"function"==typeof define&&define.amd?define(["exports","@apigo.cc/state","@apigo.cc/bootstrap"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).ApigoBase={},t.ApigoState)}(this,function(t,e){"use strict";const i={get:({url:t,...e})=>i.request({url:t,method:"GET",...e}),post:({url:t,data:e,...a})=>i.request({url:t,method:"POST",data:e,...a}),put:({url:t,data:e,...a})=>i.request({url:t,method:"PUT",data:e,...a}),delete:({url:t,...e})=>i.request({url:t,method:"DELETE",...e}),head:({url:t,...e})=>i.request({url:t,method:"HEAD",...e}),request:async({url:t,method:e="POST",data:i,headers:a={},responseType:n,timeout:s=1e4})=>{var o;const l={method:e=e.toUpperCase(),signal:null==(o=AbortSignal.timeout)?void 0:o.call(AbortSignal,s)};if(void 0!==i&&"GET"!==e&&"HEAD"!==e){if(i instanceof HTMLFormElement&&(i=new FormData(i)),i&&"object"==typeof i&&!(i instanceof FormData)&&!(i instanceof ArrayBuffer||ArrayBuffer.isView(i))&&Object.values(i).some(t=>t instanceof File||t instanceof Blob||t instanceof FileList||Array.isArray(t)&&t.some(t=>t instanceof File||t instanceof Blob))){const t=new FormData;for(const[e,a]of Object.entries(i))a instanceof FileList||Array.isArray(a)?Array.from(a).forEach(i=>t.append(e,i)):null!=a&&t.append(e,a);i=t}i instanceof FormData?delete a["Content-Type"]:"string"==typeof i||i instanceof ArrayBuffer||ArrayBuffer.isView(i)||(i=JSON.stringify(i),a["Content-Type"]||(a["Content-Type"]="application/json")),l.body=i}Object.keys(a).length&&(l.headers=a);const r={error:null,ok:null,status:0,headers:{},responseType:"",result:null};try{const e=await fetch(t,l);if(Object.assign(r,{ok:e.ok,status:e.status,headers:Object.fromEntries(e.headers.entries())}),!n){const t=e.headers.get("Content-Type")||"";n=t.includes("application/json")?"json":/image|video|audio|pdf|zip|octet-stream/.test(t)?"binary":"text",r.responseType=n}!1===r.ok&&(r.error=(r.statusText||"HTTP "+r.status+" error")+" for "+t),r.result="json"===n?await e.json():"binary"===n?await e.arrayBuffer():await e.text()}catch(t){Object.assign(r,{error:t.message||String(t),ok:!1})}return r}},a=e.Component.register("API",t=>{t.request=e.NewState({url:"",method:"GET",headers:{},data:null,timeout:1e4,responseType:""}),t.response=e.NewState({loading:!1,ok:null,status:null,error:null,headers:{},responseType:"",result:null}),t.result=e.NewState(),t.do=(e={})=>new Promise((a,n)=>{const s={...t.request,...e};if(!s.url)throw new Error(".url is required");s.headers={...t.request.headers,...e.headers},t.response.loading=!0,i.request(s).then(e=>{if(Object.keys(e).forEach(i=>{"result"!==i&&(t.response[i]=e[i])}),e.result&&"object"==typeof e.result&&t.result&&"object"==typeof t.result?Object.assign(t.result,e.result):t.result=e.result,t.response.loading=!1,!1===e.ok)throw new Error(e.error);if("object"==typeof e.result&&e.result.error)throw new Error(e.result.error);t.dispatchEvent(new CustomEvent("response",{detail:e,bubbles:!1})),a(e)}).catch(i=>{var a;!e.noui&&(null==(a=globalThis.UI)?void 0:a.toast)&&UI.toast(i.message,{type:"danger"}),t.dispatchEvent(new CustomEvent("error",{detail:i,bubbles:!0})),n(i)})});let a=null;t.request.__watch(null,()=>{t.hasAttribute("auto")&&t.request.url&&(a||(a=Promise.resolve().then(()=>{t.do(),a=null})))})}),n={};e.Component.register("Modal",t=>{t.modal=new bootstrap.Modal(t),t.addEventListener("bind",e=>{e.detail?t.modal.show():t.modal.hide()}),t.addEventListener("hide.bs.modal",()=>{var e;null==(e=document.activeElement)||e.blur(),t.dispatchEvent(new CustomEvent("change",{bubbles:!1,detail:!1}))}),e.Util.copyFunction(t,t.modal,"show","hide")},e.Util.makeDom('\n\n')),e.Component.register("Dialog",e.Component.getSetupFunction("Modal"),e.Util.makeDom('\n\n'));let s=0;n.showDialog=function({title:t="",message:e="",buttons:i=["{#Close#}"],type:a="body"}){const n=document.body.appendChild(document.createElement("Dialog"));return n.style.zIndex=2e3+ ++s,Promise.resolve().then(()=>{Object.assign(n.state,{message:e,title:t,type:a,buttons:i}),n.show()}),new Promise(t=>{n.addEventListener("change",e=>{s--,t(n.result||0),n.remove()})})},n.alert=function(t,e={}){return n.showDialog({message:t,...e})},n.confirm=function(t,e={}){return new Promise(i=>n.showDialog({message:t,buttons:["{#Cancel#}","{#Confirm#}"],...e}).then(t=>i(t>=2)).catch(()=>i(!1)))},e.Component.register("Toast",t=>{t.toast=new bootstrap.Toast(t,{autohide:t.state.delay>0}),e.Util.copyFunction(t,t.toast,"show","hide"),t.addEventListener("show.bs.toast",()=>{if(t.state.delay>0){let e;const i=()=>{t.state.left=t.state.delay/1e3,e=setInterval(()=>{(!t.isConnected||--t.state.left<=0)&&clearInterval(e)},1e3)};i(),t.addEventListener("mouseenter",()=>{clearInterval(e),t.state.left=void 0}),t.addEventListener("mouseleave",i)}})},e.Util.makeDom('\n\n'),e.Util.makeDom('')),n.toast=function(t,i={}){const a=i.delay??5e3,n=document.createElement("Toast");n.state={delay:a,left:a?a/1e3:void 0,type:i.type||"primary",message:t,buttons:i.buttons||[]},e.$(`[toast-container="${i.container||"default"}"]`).appendChild(n),Promise.resolve().then(()=>n.show())},n.toastConfirm=function(t,e={}){return new Promise(i=>n.toast(t,{buttons:["{#Confirm#}"],...e}).then(t=>i(1===t)).catch(()=>i(!1)))};const o=e.Util.makeDom('\n\n'),l=e.Util.makeDom("");e.Component.register("AutoForm",t=>{t.state.schema||(t.state.schema=[]);const a=t=>t&&"object"==typeof t&&!t.__isProxy?e.NewState(t):t;t.state.__watch("data",e=>t.data=a(e)),t.data=a(t.state.data||{}),t.vertical=t.hasAttribute("vertical"),t.horizontal=t.hasAttribute("horizontal"),t.inline=t.hasAttribute("inline"),t.nobutton=t.hasAttribute("nobutton"),t.request={method:"POST"},t.response={},t.result=null,t.form=e.$(t,"form"),t.submit=(e={})=>{var a,n;if(!t.form.reportValidity())return null==(n=null==(a=globalThis.UI)?void 0:a.toast)?void 0:n.call(a,"{#verify failed#}",{type:"danger"});if(!t.dispatchEvent(new CustomEvent("submit",{detail:t.data,cancelable:!0,bubbles:!1})))return;const s={...t.request,data:t.data,noui:!0,...e};let o=null;if(t.api)o=t.api.do(s);else{if(!t.request.url)return console.warn("{#please config .api or .request.url to auto submit#}");o=i.request(s)}o.then(e=>{if(t.response=e,t.result=e.result,"object"==typeof e.result&&e.result.error)throw new Error(e.result.error);t.dispatchEvent(new CustomEvent("response",{detail:e,bubbles:!1}))}).catch(e=>{var i;(null==(i=globalThis.UI)?void 0:i.toast)&&UI.toast(e.message,{type:"danger"}),t.dispatchEvent(new CustomEvent("error",{detail:e,bubbles:!0}))})},t.checkIf=e=>{if(!e.if)return!0;try{return new Function("Hash","LocalStorage","State","item","data","return "+e.if).call(t,globalThis.Hash,globalThis.LocalStorage,globalThis.State,e,t.data)}catch(t){return!1}}},o,l);const r=t=>{let e=t.querySelector("[control-wrapper]");if(e)return e;for(const i of t.querySelectorAll("template"))if(e=r(i.content),e)return e;return null},d={customTypes:[],register:(t,e)=>{const i=e||t;d.customTypes.find(e=>e.name===t)||(d.customTypes.push({name:t,typeName:i}),d._addAutoFormComponent(t,i))},_addAutoFormComponent:(t,i)=>{const a=r(o);if(a){const n=e.Util.makeDom(`<${t} $if="item.type?.toLowerCase() === '${i.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="this.data[item.name]" class="w-100">${t}>`);a.appendChild(n)}}};e.Component.register("TagsInput",t=>{t._thisObj=t,t.addEventListener("bind",e=>{t.state.tags=Array.isArray(e.detail)?e.detail:[]})},e.Util.makeDom(`\n\n \n \n \n \n
\n`),e.Util.makeDom("")),d.register("TagsInput"),e.Component.register("DatePicker",t=>{t._thisObj=t,t.state=e.NewState({start:"",end:""}),t.addEventListener("bind",e=>{var i,a,n;t.state.start=e.detail||"";const s=t.closest("AutoForm"),o=t.getAttribute("name"),l=null==(a=null==(i=null==s?void 0:s.state)?void 0:i.schema)?void 0:a.find(t=>t.name===o),r=(null==(n=null==l?void 0:l.setting)?void 0:n.rangeEnd)||t.rangeEnd;s&&r&&(t.state.end=s.data[r]||"")}),Object.defineProperty(t,"isRange",{get:()=>{var e,i,a;const n=t.closest("AutoForm"),s=t.getAttribute("name"),o=null==(i=null==(e=null==n?void 0:n.state)?void 0:e.schema)?void 0:i.find(t=>t.name===s);return!(!(null==(a=null==o?void 0:o.setting)?void 0:a.rangeEnd)&&!t.rangeEnd)}}),Object.defineProperty(t,"value",{get:()=>t.state.start,set:e=>{t.state.start=e||""}}),t.updateStart=e=>{t.state.start=e,t.dispatchEvent(new CustomEvent("change",{bubbles:!0,detail:e}))},t.updateEnd=e=>{var i,a,n;t.state.end=e;const s=t.closest("AutoForm"),o=t.getAttribute("name"),l=null==(a=null==(i=null==s?void 0:s.state)?void 0:i.schema)?void 0:a.find(t=>t.name===o),r=(null==(n=null==l?void 0:l.setting)?void 0:n.rangeEnd)||t.rangeEnd;s&&r&&(s.data[r]=e)}},e.Util.makeDom('\n\n \n \n -\n \n \n
\n')),e.Component.register("ColorPicker",t=>{t._thisObj=t,t.state=e.NewState({value:"#000000"}),t.addEventListener("bind",e=>{t.state.value=e.detail||"#000000"}),Object.defineProperty(t,"value",{get:()=>t.state.value,set:e=>{t.state.value=e||"#000000"}}),t.updateValue=e=>{t.state.value=e,t.dispatchEvent(new CustomEvent("change",{bubbles:!0,detail:e}))}},e.Util.makeDom('\n\n \n \n
\n'));const c=["alarm","archive","arrow-left","arrow-right","bag","bank","basket","bell","bookmark","box","briefcase","calendar","camera","cart","chat","check","chevron-down","chevron-left","chevron-right","chevron-up","clock","cloud","code","collection","command","cpu","credit-card","cup","dash","database","display","door-closed","download","droplet","earbuds","edit","egg","eject","envelope","eraser","eye","file","filter","flag","folder","gear","gem","gift","graph-up","grid","hammer","hand-thumbs-up","heart","house","image","inbox","info-circle","journal","key","laptop","layers","layout-text-sidebar-reverse","lightbulb","link","list","lock","map","mic","moon","mouse","music-note","newspaper","palette","paperclip","pause","pencil","person","phone","pie-chart","play","plus","printer","puzzle","question-circle","reception-4","record","reply","rss","save","search","send","server","share","shield","shop","shuffle","skip-end","skip-start","slash","sliders","smartphone","speaker","speedometer","spellcheck","square","star","stickies","stop","stopwatch","suit-heart","sun","table","tag","tags","telephone","terminal","text-paragraph","thermometer","three-dots","ticket","tools","trash","trophy","truck","tv","umbrella","unlock","upload","vector-pen","wallet","watch","wifi","window","wrench","x","zoom-in","zoom-out","activity","at","award","backspace","badge-3d","badge-4k","badge-8k","badge-ad","badge-ar","badge-cc","badge-hd","badge-tm","badge-vo","badge-vr","badge-wc","bar-chart","battery","bicycle","binoculars","blockquote-left","blockquote-right","book","bookshelf","bootstrap","border-all","border-bottom","border-center","border-inner","border-left","border-middle","border-outer","border-right","border-style","border-top","border-width","bounding-box","box-arrow-down","box-arrow-in-down","box-arrow-in-left","box-arrow-in-right","box-arrow-in-up","box-arrow-left","box-arrow-right","box-arrow-up","box-seam","brightness-alt-high","brightness-alt-low","brightness-high","brightness-low","broadcast","brush","bucket","bug","building","bullseye","calculator","calendar-check","calendar-date","calendar-day","calendar-event","calendar-minus","calendar-month","calendar-plus","calendar-range","calendar-week","calendar-x","calendar2","calendar3","calendar4","camera-reels","camera-video","capslock","card-checklist","card-heading","card-image","card-list","card-text","caret-down","caret-left","caret-right","caret-up","cart-check","cart-dash","cart-plus","cart-x","cash","cash-stack","cast","chat-dots","chat-left","chat-quote","chat-right","chat-square","chat-text","check-all","check-circle","check-square","circle","clipboard","cloud-arrow-down","cloud-arrow-up","cloud-check","cloud-download","cloud-fog","cloud-hail","cloud-lightning","cloud-minus","cloud-moon","cloud-plus","cloud-rain","cloud-slash","cloud-snow","cloud-sun","cloud-upload","clouds","cloudy","code-slash","code-square","collection-play","columns","columns-gap","compass","cone","cone-striped","controller","credit-card-2-back","credit-card-2-front","crop","cup-straw","cursor","dash-circle","dash-square","diagram-2","diagram-3","diamond","dice-1","dice-2","dice-3","dice-4","dice-5","dice-6","disc","discord","distribute-horizontal","distribute-vertical","door-open","dot","droplet-half","easel","egg-fried","emoji-angry","emoji-dizzy","emoji-expressionless","emoji-frown","emoji-heart-eyes","emoji-laughing","emoji-neutral","emoji-smile","emoji-sunglasses","emoji-wink","envelope-open","exclamation","exclamation-circle","exclamation-diamond","exclamation-octagon","exclamation-square","exclamation-triangle","eye-slash","eyedropper","facebook","file-arrow-down","file-arrow-up","file-binary","file-break","file-check","file-code","file-diff","file-earmark","file-excel","file-image","file-lock","file-medical","file-minus","file-music","file-pdf","file-person","file-play","file-plus","file-post","file-ppt","file-richtext","file-slides","file-spreadsheet","file-text","file-word","file-zip","files","film","filter-circle","filter-left","filter-right","filter-square","fingerprint","flower1","flower2","flower3","folder-check","folder-minus","folder-plus","folder-symlink","folder-x","folder2-open","fonts","forward","front","fullscreen","fullscreen-exit","funnel","gear-wide","gender-female","gender-male","gender-trans","geo","geo-alt","github","globe","google","graph-down","grid-1x2","grid-3x2","grid-3x3","grip-horizontal","grip-vertical","hand-index","hand-thumbs-down","handbag","hash","headphones","headset","heart-half","heptagon","hourglass","hourglass-bottom","hourglass-split","hourglass-top","house-door","hr","hurricane","image-alt","images","infinity","input-cursor","instagram","intersect","journal-album","journal-arrow-down","journal-arrow-up","journal-bookmark","journal-check","journal-code","journal-medical","journal-minus","journal-plus","journal-richtext","journal-text","journal-x","journals","justify","kanban","keyboard","ladder","lamp","layers-half","layout-sidebar","layout-split","layout-three-columns","life-preserver","lightbulb-off","lightning","lightning-charge","link-45deg","linkedin","list-check","list-nested","list-ol","list-stars","list-task","list-ul","mailbox","markdown","mask","mastodon","megaphone","menu-app","menu-button","messenger","mic-mute","minecart","minecart-loaded","moisture","mouse2","mouse3","music-note-beamed","music-note-list","music-player","node-minus","node-plus","nut","octagon","option","outlet","paint-bucket","patch-check","patch-exclamation","patch-minus","patch-plus","patch-question","pause-btn","pause-circle","peace","pen","pencil-square","pentagon","person-badge","person-bounding-box","person-circle","person-lines-fill","phone-landscape","phone-vibrate","pie-chart-fill","pin","pin-angle","pin-fill","pin-map","pip","play-btn","play-circle","plug","plus-circle","plus-square","power","question","question-diamond","question-square","rainbow","receipt","receipt-cutoff","reception-0","reception-1","reception-2","reception-3","record-btn","record-circle","record2","recycle","reddit","reply-all","router","rulers","safe","save2","sd-card","segmented-nav","shield-check","shield-exclamation","shield-lock","shield-shaded","shield-slash","shift","signpost","signpost-2","signpost-split","sim","skip-backward","skip-forward","slack","slash-circle","slash-square","smartwatch","snow","snow2","snow3","sort-alpha-down","sort-alpha-up","sort-numeric-down","sort-numeric-up","soundwave","speedometer2","square-half","stack","star-half","stars","stop-btn","stop-circle","suit-club","suit-diamond","suit-spade","sunglasses","sunrise","sunset","symmetry-horizontal","symmetry-vertical","tablet","tablet-landscape","telegram","telephone-forward","telephone-inbound","telephone-outbound","telephone-plus","telephone-x","text-center","text-indent-left","text-indent-right","text-left","text-right","thermometer-half","thermometer-high","thermometer-low","thermometer-snow","thermometer-sun","three-dots-vertical","toggle-off","toggle-on","toggle2-off","toggle2-on","tornado","translate","trash2","tree","truck-flatbed","tsunami","type","type-bold","type-h1","type-h2","type-h3","type-italic","type-strikethrough","type-underline","ui-checks","ui-checks-grid","ui-radios","ui-radios-grid","union","upc","upc-scan","view-list","view-stacked","vinyl","voicemail","volume-down","volume-mute","volume-off","volume-up","vr","wallet2","water","whatsapp","wifi-1","wifi-2","wifi-off","wind","window-dock","window-sidebar","x-circle","x-diamond","x-octagon","x-square","youtube"];e.Component.register("IconPicker",t=>{t._thisObj=t,t.state=e.NewState({value:"",search:"",open:!1}),t.addEventListener("bind",e=>{t.state.value=e.detail||""}),Object.defineProperty(t,"value",{get:()=>t.state.value,set:e=>{t.state.value=e||""}}),Object.defineProperty(t,"filteredIcons",{get:()=>{var e;const i=(null==(e=t.state.search)?void 0:e.toLowerCase())||"";return c.filter(t=>t.includes(i))}}),t.selectIcon=e=>{t.state.value=e,t.state.open=!1,t.dispatchEvent(new CustomEvent("change",{bubbles:!0,detail:e}))},t.toggle=()=>{t.state.open=!t.state.open,t.state.open&&setTimeout(()=>{var i;null==(i=e.$(t,"input"))||i.focus()},10)};const i=e=>{t.contains(e.target)||(t.state.open=!1)};window.addEventListener("click",i),t.addEventListener("remove",()=>window.removeEventListener("click",i))},e.Util.makeDom('\n\n
\n
\n
\n
\n
\n \n \n
No icons found
\n
\n
\n
\n'),e.Util.makeDom("")),d.register("DatePicker"),d.register("ColorPicker"),d.register("IconPicker");const m=(t={})=>{const i=new Map,a=new Map;let n=1;const s=e.Util.newAvg();let o=0,l=0,r=0,d=null,c=null,m=!1;const u=t.itemHeight||null;return{reset:(t,e)=>{if(m=!1,i.clear(),a.clear(),s.clear(),r=0,d=null,c=null,!(null==t?void 0:t.length))return[];const p=t.length;n=Math.ceil(Math.sqrt(p))||10;const h=window.getComputedStyle(e);o=parseFloat(h.paddingTop)||0,l=parseFloat(h.rowGap)||0;const b=Math.max(10,Math.ceil((e.clientHeight||100)/(u||32)));return t.slice(0,Math.min(3*b,p))},init:(t,e)=>{if(m)return;const o=t.length;let l=u||s.get()||32;o>0&&"object"==typeof t[0]&&null!==t[0]&&t[0]._itemHeight&&(l=t[0]._itemHeight),s.add(l),null===d&&(d=0,c=0);for(let e=0;e{if(0===e.offsetHeight)return;if(null===d){const t=window.getComputedStyle(e);d=parseFloat(t.marginTop)||0,c=parseFloat(t.marginBottom)||0}0!==t||r||(r=d);const o=e.offsetHeight+d+c+l,m=i.get(t);if(o!==m){i.set(t,o),s.add(o);const e=o-(m||0),l=t-t%n;a.has(l)&&a.set(l,a.get(l)+e)}},calc:(t,e)=>{if(!m||!e)return null;const d=e.length,c=Math.max(16,s.get()||32);let u=Math.max(10,Math.ceil((t.clientHeight||100)/c)),p=o+r+l,h=0,b=0,f=0,g=0,v=[];const y=t.scrollTop;let x=0;for(let t=0;t2*d)throw new Error("VirtualScroll infinite loop");if(0===b){const s=a.get(t);if(s&&p+s<=y&&t+n0?l:0)),postHeight:h>0?Math.max(0,h-2*l):0,renderedList:v,listStartIndex:f}}}};e.Component.register("List",t=>{t.mode=t.getAttribute("mode")||"normal",t.fast=t.hasAttribute("fast"),t.collapsible=t.hasAttribute("collapsible");const i=t.fast?t.querySelector(".vs-pad-top"):null,a=t.fast?t.querySelector(".vs-pad-bottom"):null,n={idfield:"id",labelfield:"label",summaryfield:"summary",groupidfield:"id",grouplabelfield:"label",groupsummaryfield:"summary",groupfield:"group",parentfield:"parent",groupicon:"folder",itemicon:"file"};t.collapsed=e.NewState({}),t.state.renderedList=[];const s=()=>{e.Util.updateDefaults(t,n);const i=t.state.list||[],a=[];if("group"===t.mode){const e={};i.forEach(i=>{var a;return(e[a=i[t.groupfield]]??(e[a]=[])).push(i)}),(t.state.groups||[]).forEach(i=>{a.push({type:"group",...i});const n=e[i[t.groupidfield]];n&&n.forEach(t=>a.push({type:"item",...t}))})}else if("tree"===t.mode){const e={};i.forEach(i=>{var a;return(e[a=i[t.parentfield]||""]??(e[a]=[])).push(i)});const n=(i,s,o)=>i.forEach(i=>{var l;const r=i[t.idfield],d=!!(null==(l=e[r])?void 0:l.length),c=t.collapsed[r];a.push({type:"item",...i,_level:s,_hasChildren:d,_parents:o}),d&&!c&&n(e[r],s+1,[...o,r])});n(e[""]||[],0,[])}else i.forEach(t=>a.push({type:"item",...t}));t.state.flatList=a};t.state.__watch("list",s);const o=t.fast?m():null;let l=!1;t.refresh=()=>{if(t.fast&&!l){l=!0;try{const e=o.calc(t,t.state.flatList);e&&(i&&(i.style.height=`${e.prevHeight}px`),a&&(a.style.height=`${e.postHeight}px`),t.state.listStartIndex=e.listStartIndex,t.state.renderedList=e.renderedList)}finally{setTimeout(()=>{l=!1},0)}}},t.onItemUpdate=(e,i)=>{t.fast&&o.update(e+(t.state.listStartIndex||0),i)},t.state.__watch("flatList",e=>{t.fast?(i&&(i.style.height="0px"),a&&(a.style.height="0px"),t.state.listStartIndex=0,t.state.renderedList=o.reset(e,t)||[],setTimeout(()=>{t.state.flatList===e&&o.init(e,t.refresh)})):t.state.renderedList=e}),t.selectItem=(e,i)=>{t.hasAttribute("auto-select")&&(t.state.selectedItem=t.state.selectedItem===e[t.idfield]?null:e[t.idfield]),t.dispatchEvent(new CustomEvent("itemclick",{bubbles:!1,detail:{item:e,index:i+(t.fast&&t.state.listStartIndex||0)}}))},t.selectGroup=(e,i)=>{t.hasAttribute("auto-select-group")&&(t.state.selectedGroup=t.state.selectedGroup===e[t.groupidfield]?null:e[t.groupidfield]),t.dispatchEvent(new CustomEvent("groupclick",{bubbles:!1,detail:{item:e,index:i}}))},t.toggleCollapse=e=>{t.collapsible&&e._hasChildren&&(t.collapsed[e[t.idfield]]=!t.collapsed[e[t.idfield]],s())},s()},e.Util.makeDom('\n\n\t
\n\t
\n\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t
\n\t\n\t
\n
\n')),e.Component.register("Nav",t=>{t.vertical=t.hasAttribute("vertical"),t.click=(i,a)=>{i.noselect||a||(e.Hash.nav=i.name),t.dispatchEvent(new CustomEvent("nav",{detail:{item:i},bubbles:!1}))}},e.Util.makeDom('\n\n\t
\n\t\t
\n\t\n\t
\n\t\t\n\t\n\t
\n\t\t\n\t\n\t
\n\t
\n\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t\n\t\t
\n\t\n
\n'));let u=!1,p={},h={};const b={start:(t,{onmousemove:e,onmouseup:i})=>{p={x:t.clientX,y:t.clientY,w:0,h:0},h={onmousemove:e,onmouseup:i},u=!0}};"undefined"!=typeof document&&(document.addEventListener("mouseup",t=>{var e;u&&(u=!1,null==(e=h.onmouseup)||e.call(h,{event:t,...p}))}),document.addEventListener("mousemove",t=>{var e;u&&(p.w=t.clientX-p.x,p.h=t.clientY-p.y,null==(e=h.onmousemove)||e.call(h,{event:t,...p}))})),e.Component.register("Resizer",t=>{t.isVertical=t.hasAttribute("vertical");const e=parseInt(t.getAttribute("min"))||10,i=parseInt(t.getAttribute("max"))||1e3,a=t.target||t.previousElementSibling;t.addEventListener("bind",e=>{void 0!==e.detail&&null!==e.detail&&(a.style[t.isVertical?"height":"width"]=e.detail+"px")});const n=(a,n,s)=>{const o=a+(t.isVertical?s:n);return oi?i:o};t.addEventListener("mousedown",e=>{const i=t.isVertical?a.offsetHeight:a.offsetWidth;b.start(e,{onmousemove:({w:e,h:s})=>{const o=n(i,e,s);a.style[t.isVertical?"height":"width"]=o+"px",t.dispatchEvent(new CustomEvent("resizing",{detail:{oldSize:i,newSize:o},bubbles:!1}))},onmouseup:({w:e,h:a})=>{const s=n(i,e,a);t.dispatchEvent(new CustomEvent("resize",{detail:{oldSize:i,newSize:s},bubbles:!1})),t.dispatchEvent(new CustomEvent("change",{detail:s,bubbles:!1}))}})})},e.Util.makeDom("\n\n")),"undefined"!=typeof window&&window.addEventListener("beforeunload",t=>{e.State.exitBlocks>0&&t.preventDefault()});const f=document.documentElement;f.hasAttribute("$data-bs-theme")||f.hasAttribute("data-bs-theme")||f.setAttribute("$data-bs-theme","LocalStorage.darkMode?'dark':'light'"),globalThis.HTTP=i,globalThis.UI=n,globalThis.AutoForm=d,globalThis.MouseMover=b,globalThis.VirtualScroll=m;const g={HTTP:i,UI:n,AutoForm:d,MouseMover:b,VirtualScroll:m,State:e.State,List:m};"undefined"!=typeof document&&(globalThis.ApigoBase=g),Object.defineProperty(t,"State",{enumerable:!0,get:()=>e.State}),t.APIComponent=a,t.AutoForm=d,t.HTTP=i,t.MouseMover=b,t.UI=n,t.VirtualScroll=m,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@apigo.cc/state")):"function"==typeof define&&define.amd?define(["exports","@apigo.cc/state"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ApigoBase=e.ApigoBase||{},e.ApigoState)}(this,function(e,t){"use strict";const i={get:({url:e,...t})=>i.request({url:e,method:"GET",...t}),post:({url:e,data:t,...a})=>i.request({url:e,method:"POST",data:t,...a}),put:({url:e,data:t,...a})=>i.request({url:e,method:"PUT",data:t,...a}),delete:({url:e,...t})=>i.request({url:e,method:"DELETE",...t}),head:({url:e,...t})=>i.request({url:e,method:"HEAD",...t}),request:async({url:e,method:t="POST",data:i,headers:a={},responseType:s,timeout:l=1e4})=>{var n;const o={method:t=t.toUpperCase(),signal:null==(n=AbortSignal.timeout)?void 0:n.call(AbortSignal,l)};if(void 0!==i&&"GET"!==t&&"HEAD"!==t){if(i instanceof HTMLFormElement&&(i=new FormData(i)),i&&"object"==typeof i&&!(i instanceof FormData)&&!(i instanceof ArrayBuffer||ArrayBuffer.isView(i))&&Object.values(i).some(e=>e instanceof File||e instanceof Blob||e instanceof FileList||Array.isArray(e)&&e.some(e=>e instanceof File||e instanceof Blob))){const e=new FormData;for(const[t,a]of Object.entries(i))a instanceof FileList||Array.isArray(a)?Array.from(a).forEach(i=>e.append(t,i)):null!=a&&e.append(t,a);i=e}i instanceof FormData?delete a["Content-Type"]:"string"==typeof i||i instanceof ArrayBuffer||ArrayBuffer.isView(i)||(i=JSON.stringify(i),a["Content-Type"]||(a["Content-Type"]="application/json")),o.body=i}Object.keys(a).length&&(o.headers=a);const r={error:null,ok:null,status:0,headers:{},responseType:"",result:null};try{const t=await fetch(e,o);if(Object.assign(r,{ok:t.ok,status:t.status,headers:Object.fromEntries(t.headers.entries())}),!s){const e=t.headers.get("Content-Type")||"";s=e.includes("application/json")?"json":/image|video|audio|pdf|zip|octet-stream/.test(e)?"binary":"text",r.responseType=s}!1===r.ok&&(r.error=(r.statusText||"HTTP "+r.status+" error")+" for "+e),r.result="json"===s?await t.json():"binary"===s?await t.arrayBuffer():await t.text()}catch(e){Object.assign(r,{error:e.message||String(e),ok:!1})}return r}};globalThis.HTTP=i;const a={};globalThis.Component.register("Toast",e=>{e.toast=new bootstrap.Toast(e,{autohide:e.state.delay>0}),globalThis.Util.copyFunction(e,e.toast,"show","hide"),e.addEventListener("show.bs.toast",()=>{if(e.state.delay>0){let t;const i=()=>{e.state.left=e.state.delay/1e3,t=setInterval(()=>{(!e.isConnected||--e.state.left<=0)&&clearInterval(t)},1e3)};i(),e.addEventListener("mouseenter",()=>{clearInterval(t),e.state.left=void 0}),e.addEventListener("mouseleave",i)}})},globalThis.Util.makeDom('\n\n'),globalThis.Util.makeDom('')),a.toast=function(e,t={}){const i=t.delay??5e3,a=document.createElement("Toast");a.state={delay:i,left:i?i/1e3:void 0,type:t.type||"primary",message:e,buttons:t.buttons||[]},globalThis.$(`[toast-container="${t.container||"default"}"]`).appendChild(a),Promise.resolve().then(()=>a.show())},a.toastConfirm=function(e,t={}){return new Promise(i=>a.toast(e,{buttons:["{#Confirm#}"],...t}).then(e=>i(1===e)).catch(()=>i(!1)))},globalThis.UI=a;const s=globalThis.Util.makeDom('\n\n'),l=globalThis.Util.makeDom("");globalThis.Component.register("AutoForm",e=>{e.state.schema||(e.state.schema=[]);const t=e=>e&&"object"==typeof e&&!e.__isProxy?globalThis.NewState(e):e;e.state.__watch("data",i=>e.data=t(i)),e.data=t(e.state.data||{}),e.vertical=e.hasAttribute("vertical"),e.horizontal=e.hasAttribute("horizontal"),e.inline=e.hasAttribute("inline"),e.nobutton=e.hasAttribute("nobutton"),e.request={method:"POST"},e.response={},e.result=null,e.form=globalThis.$(e,"form"),e.submit=(t={})=>{var i,a;if(!e.form.reportValidity())return null==(a=null==(i=globalThis.UI)?void 0:i.toast)?void 0:a.call(i,"{#verify failed#}",{type:"danger"});if(!e.dispatchEvent(new CustomEvent("submit",{detail:e.data,cancelable:!0,bubbles:!1})))return;const s={...e.request,data:e.data,noui:!0,...t};let l=null;if(e.api)l=e.api.do(s);else{if(!e.request.url)return console.warn("{#please config .api or .request.url to auto submit#}");l=globalThis.HTTP.request(s)}l.then(t=>{if(e.response=t,e.result=t.result,"object"==typeof t.result&&t.result.error)throw new Error(t.result.error);e.dispatchEvent(new CustomEvent("response",{detail:t,bubbles:!1}))}).catch(t=>{var i;(null==(i=globalThis.UI)?void 0:i.toast)&&globalThis.UI.toast(t.message,{type:"danger"}),e.dispatchEvent(new CustomEvent("error",{detail:t,bubbles:!0}))})},e.checkIf=t=>{if(!t.if)return!0;try{return new Function("Hash","LocalStorage","State","item","data","return "+t.if).call(e,globalThis.Hash,globalThis.LocalStorage,globalThis.State,t,e.data)}catch(e){return!1}}},s,l);const n=e=>{let t=e.querySelector("[control-wrapper]");if(t)return t;for(const i of e.querySelectorAll("template"))if(t=n(i.content),t)return t;return null},o={customTypes:[],register:(e,t)=>{const i=t||e;o.customTypes.find(t=>t.name===e)||(o.customTypes.push({name:e,typeName:i}),o._addAutoFormComponent(e,i))},_addAutoFormComponent:(e,t)=>{const i=n(s);if(i){const a=globalThis.Util.makeDom(`<${e} $if="item.type?.toLowerCase() === '${t.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="this.data[item.name]" class="w-100">${e}>`);i.appendChild(a)}}};globalThis.AutoForm=o;const r=(e={})=>{const t=new Map,i=new Map;let a=1;const s=globalThis.Util.newAvg();let l=0,n=0,o=0,r=null,d=null,c=!1;const m=e.itemHeight||null;return{reset:(e,u)=>{if(c=!1,t.clear(),i.clear(),s.clear(),o=0,r=null,d=null,!(null==e?void 0:e.length))return[];const p=e.length;a=Math.ceil(Math.sqrt(p))||10;const h=window.getComputedStyle(u);l=parseFloat(h.paddingTop)||0,n=parseFloat(h.rowGap)||0;const b=Math.max(10,Math.ceil((u.clientHeight||100)/(m||32)));return e.slice(0,Math.min(3*b,p))},init:(e,l)=>{if(c)return;const n=e.length;let o=m||s.get()||32;n>0&&"object"==typeof e[0]&&null!==e[0]&&e[0]._itemHeight&&(o=e[0]._itemHeight),s.add(o),null===r&&(r=0,d=0);for(let i=0;i{if(0===l.offsetHeight)return;if(null===r){const e=window.getComputedStyle(l);r=parseFloat(e.marginTop)||0,d=parseFloat(e.marginBottom)||0}0!==e||o||(o=r);const c=l.offsetHeight+r+d+n,m=t.get(e);if(c!==m){t.set(e,c),s.add(c);const l=c-(m||0),n=e-e%a;i.has(n)&&i.set(n,i.get(n)+l)}},calc:(e,r)=>{if(!c||!r)return null;const d=r.length,m=Math.max(16,s.get()||32);let u=Math.max(10,Math.ceil((e.clientHeight||100)/m)),p=l+o+n,h=0,b=0,g=0,f=0,v=[];const y=e.scrollTop;let x=0;for(let e=0;e2*d)throw new Error("VirtualScroll infinite loop");if(0===b){const s=i.get(e);if(s&&p+s<=y&&e+a0?n:0)),postHeight:h>0?Math.max(0,h-2*n):0,renderedList:v,listStartIndex:g}}}};globalThis.VirtualScroll=r;let d=!1,c={},m={};const u={start:(e,{onmousemove:t,onmouseup:i})=>{c={x:e.clientX,y:e.clientY,w:0,h:0},m={onmousemove:t,onmouseup:i},d=!0}};"undefined"!=typeof document&&(document.addEventListener("mouseup",e=>{var t;d&&(d=!1,null==(t=m.onmouseup)||t.call(m,{event:e,...c}))}),document.addEventListener("mousemove",e=>{var t;d&&(c.w=e.clientX-c.x,c.h=e.clientY-c.y,null==(t=m.onmousemove)||t.call(m,{event:e,...c}))})),globalThis.MouseMover=u;const p=globalThis.Component.register("API",e=>{e.request=globalThis.NewState({url:"",method:"GET",headers:{},data:null,timeout:1e4,responseType:""}),e.response=globalThis.NewState({loading:!1,ok:null,status:null,error:null,headers:{},responseType:"",result:null}),e.result=globalThis.NewState(),e.do=(t={})=>new Promise((i,a)=>{const s={...e.request,...t};if(!s.url)throw new Error(".url is required");s.headers={...e.request.headers,...t.headers},e.response.loading=!0,globalThis.HTTP.request(s).then(t=>{if(Object.keys(t).forEach(i=>{"result"!==i&&(e.response[i]=t[i])}),t.result&&"object"==typeof t.result&&e.result&&"object"==typeof e.result?Object.assign(e.result,t.result):e.result=t.result,e.response.loading=!1,!1===t.ok)throw new Error(t.error);if("object"==typeof t.result&&t.result.error)throw new Error(t.result.error);e.dispatchEvent(new CustomEvent("response",{detail:t,bubbles:!1})),i(t)}).catch(i=>{var s;!t.noui&&(null==(s=globalThis.UI)?void 0:s.toast)&&globalThis.UI.toast(i.message,{type:"danger"}),e.dispatchEvent(new CustomEvent("error",{detail:i,bubbles:!0})),a(i)})});let t=null;e.request.__watch(null,()=>{e.hasAttribute("auto")&&e.request.url&&(t||(t=Promise.resolve().then(()=>{e.do(),t=null})))})});globalThis.Component.register("Modal",e=>{e.modal=new bootstrap.Modal(e),e.addEventListener("bind",t=>{t.detail?e.modal.show():e.modal.hide()}),e.addEventListener("hide.bs.modal",()=>{var t;null==(t=document.activeElement)||t.blur(),e.dispatchEvent(new CustomEvent("change",{bubbles:!1,detail:!1}))}),globalThis.Util.copyFunction(e,e.modal,"show","hide")},globalThis.Util.makeDom('\n\n')),globalThis.Component.register("Dialog",globalThis.Component.getSetupFunction("Modal"),globalThis.Util.makeDom('\n\n'));let h=0;globalThis.UI.showDialog=function({title:e="",message:t="",buttons:i=["{#Close#}"],type:a="body"}){const s=document.body.appendChild(document.createElement("Dialog"));return s.style.zIndex=2e3+ ++h,Promise.resolve().then(()=>{Object.assign(s.state,{message:t,title:e,type:a,buttons:i}),s.show()}),new Promise(e=>{s.addEventListener("change",t=>{h--,e(s.result||0),s.remove()})})},globalThis.UI.alert=function(e,t={}){return globalThis.UI.showDialog({message:e,...t})},globalThis.UI.confirm=function(e,t={}){return new Promise(i=>globalThis.UI.showDialog({message:e,buttons:["{#Cancel#}","{#Confirm#}"],...t}).then(e=>i(e>=2)).catch(()=>i(!1)))},globalThis.Component.register("TagsInput",e=>{e._thisObj=e,e.addEventListener("bind",t=>{e.state.tags=Array.isArray(t.detail)?t.detail:[]})},globalThis.Util.makeDom(`\n\n \n \n \n \n
\n`),globalThis.Util.makeDom("")),globalThis.AutoForm&&globalThis.AutoForm.register("TagsInput"),globalThis.Component.register("DatePicker",e=>{e._thisObj=e,e.state=globalThis.NewState({start:"",end:""}),e.addEventListener("bind",t=>{var i,a,s;e.state.start=t.detail||"";const l=e.closest("AutoForm"),n=e.getAttribute("name"),o=null==(a=null==(i=null==l?void 0:l.state)?void 0:i.schema)?void 0:a.find(e=>e.name===n),r=(null==(s=null==o?void 0:o.setting)?void 0:s.rangeEnd)||e.rangeEnd;l&&r&&(e.state.end=l.data[r]||"")}),Object.defineProperty(e,"isRange",{get:()=>{var t,i,a;const s=e.closest("AutoForm"),l=e.getAttribute("name"),n=null==(i=null==(t=null==s?void 0:s.state)?void 0:t.schema)?void 0:i.find(e=>e.name===l);return!(!(null==(a=null==n?void 0:n.setting)?void 0:a.rangeEnd)&&!e.rangeEnd)}}),Object.defineProperty(e,"value",{get:()=>e.state.start,set:t=>{e.state.start=t||""}}),e.updateStart=t=>{e.state.start=t,e.dispatchEvent(new CustomEvent("change",{bubbles:!0,detail:t}))},e.updateEnd=t=>{var i,a,s;e.state.end=t;const l=e.closest("AutoForm"),n=e.getAttribute("name"),o=null==(a=null==(i=null==l?void 0:l.state)?void 0:i.schema)?void 0:a.find(e=>e.name===n),r=(null==(s=null==o?void 0:o.setting)?void 0:s.rangeEnd)||e.rangeEnd;l&&r&&(l.data[r]=t)}},globalThis.Util.makeDom('\n\n \n \n -\n \n \n
\n')),globalThis.AutoForm&&globalThis.AutoForm.register("DatePicker"),globalThis.Component.register("ColorPicker",e=>{e._thisObj=e,e.state=globalThis.NewState({value:"#000000"}),e.addEventListener("bind",t=>{e.state.value=t.detail||"#000000"}),Object.defineProperty(e,"value",{get:()=>e.state.value,set:t=>{e.state.value=t||"#000000"}}),e.updateValue=t=>{e.state.value=t,e.dispatchEvent(new CustomEvent("change",{bubbles:!0,detail:t}))}},globalThis.Util.makeDom('\n\n \n \n
\n')),globalThis.AutoForm&&globalThis.AutoForm.register("ColorPicker");const b=["alarm","archive","arrow-left","arrow-right","bag","bank","basket","bell","bookmark","box","briefcase","calendar","camera","cart","chat","check","chevron-down","chevron-left","chevron-right","chevron-up","clock","cloud","code","collection","command","cpu","credit-card","cup","dash","database","display","door-closed","download","droplet","earbuds","edit","egg","eject","envelope","eraser","eye","file","filter","flag","folder","gear","gem","gift","graph-up","grid","hammer","hand-thumbs-up","heart","house","image","inbox","info-circle","journal","key","laptop","layers","layout-text-sidebar-reverse","lightbulb","link","list","lock","map","mic","moon","mouse","music-note","newspaper","palette","paperclip","pause","pencil","person","phone","pie-chart","play","plus","printer","puzzle","question-circle","reception-4","record","reply","rss","save","search","send","server","share","shield","shop","shuffle","skip-end","skip-start","slash","sliders","smartphone","speaker","speedometer","spellcheck","square","star","stickies","stop","stopwatch","suit-heart","sun","table","tag","tags","telephone","terminal","text-paragraph","thermometer","three-dots","ticket","tools","trash","trophy","truck","tv","umbrella","unlock","upload","vector-pen","wallet","watch","wifi","window","wrench","x","zoom-in","zoom-out","activity","at","award","backspace","badge-3d","badge-4k","badge-8k","badge-ad","badge-ar","badge-cc","badge-hd","badge-tm","badge-vo","badge-vr","badge-wc","bar-chart","battery","bicycle","binoculars","blockquote-left","blockquote-right","book","bookshelf","bootstrap","border-all","border-bottom","border-center","border-inner","border-left","border-middle","border-outer","border-right","border-style","border-top","border-width","bounding-box","box-arrow-down","box-arrow-in-down","box-arrow-in-left","box-arrow-in-right","box-arrow-in-up","box-arrow-left","box-arrow-right","box-arrow-up","box-seam","brightness-alt-high","brightness-alt-low","brightness-high","brightness-low","broadcast","brush","bucket","bug","building","bullseye","calculator","calendar-check","calendar-date","calendar-day","calendar-event","calendar-minus","calendar-month","calendar-plus","calendar-range","calendar-week","calendar-x","calendar2","calendar3","calendar4","camera-reels","camera-video","capslock","card-checklist","card-heading","card-image","card-list","card-text","caret-down","caret-left","caret-right","caret-up","cart-check","cart-dash","cart-plus","cart-x","cash","cash-stack","cast","chat-dots","chat-left","chat-quote","chat-right","chat-square","chat-text","check-all","check-circle","check-square","circle","clipboard","cloud-arrow-down","cloud-arrow-up","cloud-check","cloud-download","cloud-fog","cloud-hail","cloud-lightning","cloud-minus","cloud-moon","cloud-plus","cloud-rain","cloud-slash","cloud-snow","cloud-sun","cloud-upload","clouds","cloudy","code-slash","code-square","collection-play","columns","columns-gap","compass","cone","cone-striped","controller","credit-card-2-back","credit-card-2-front","crop","cup-straw","cursor","dash-circle","dash-square","diagram-2","diagram-3","diamond","dice-1","dice-2","dice-3","dice-4","dice-5","dice-6","disc","discord","distribute-horizontal","distribute-vertical","door-open","dot","droplet-half","easel","egg-fried","emoji-angry","emoji-dizzy","emoji-expressionless","emoji-frown","emoji-heart-eyes","emoji-laughing","emoji-neutral","emoji-smile","emoji-sunglasses","emoji-wink","envelope-open","exclamation","exclamation-circle","exclamation-diamond","exclamation-octagon","exclamation-square","exclamation-triangle","eye-slash","eyedropper","facebook","file-arrow-down","file-arrow-up","file-binary","file-break","file-check","file-code","file-diff","file-earmark","file-excel","file-image","file-lock","file-medical","file-minus","file-music","file-pdf","file-person","file-play","file-plus","file-post","file-ppt","file-richtext","file-slides","file-spreadsheet","file-text","file-word","file-zip","files","film","filter-circle","filter-left","filter-right","filter-square","fingerprint","flower1","flower2","flower3","folder-check","folder-minus","folder-plus","folder-symlink","folder-x","folder2-open","fonts","forward","front","fullscreen","fullscreen-exit","funnel","gear-wide","gender-female","gender-male","gender-trans","geo","geo-alt","github","globe","google","graph-down","grid-1x2","grid-3x2","grid-3x3","grip-horizontal","grip-vertical","hand-index","hand-thumbs-down","handbag","hash","headphones","headset","heart-half","heptagon","hourglass","hourglass-bottom","hourglass-split","hourglass-top","house-door","hr","hurricane","image-alt","images","infinity","input-cursor","instagram","intersect","journal-album","journal-arrow-down","journal-arrow-up","journal-bookmark","journal-check","journal-code","journal-medical","journal-minus","journal-plus","journal-richtext","journal-text","journal-x","journals","justify","kanban","keyboard","ladder","lamp","layers-half","layout-sidebar","layout-split","layout-three-columns","life-preserver","lightbulb-off","lightning","lightning-charge","link-45deg","linkedin","list-check","list-nested","list-ol","list-stars","list-task","list-ul","mailbox","markdown","mask","mastodon","megaphone","menu-app","menu-button","messenger","mic-mute","minecart","minecart-loaded","moisture","mouse2","mouse3","music-note-beamed","music-note-list","music-player","node-minus","node-plus","nut","octagon","option","outlet","paint-bucket","patch-check","patch-exclamation","patch-minus","patch-plus","patch-question","pause-btn","pause-circle","peace","pen","pencil-square","pentagon","person-badge","person-bounding-box","person-circle","person-lines-fill","phone-landscape","phone-vibrate","pie-chart-fill","pin","pin-angle","pin-fill","pin-map","pip","play-btn","play-circle","plug","plus-circle","plus-square","power","question","question-diamond","question-square","rainbow","receipt","receipt-cutoff","reception-0","reception-1","reception-2","reception-3","record-btn","record-circle","record2","recycle","reddit","reply-all","router","rulers","safe","save2","sd-card","segmented-nav","shield-check","shield-exclamation","shield-lock","shield-shaded","shield-slash","shift","signpost","signpost-2","signpost-split","sim","skip-backward","skip-forward","slack","slash-circle","slash-square","smartwatch","snow","snow2","snow3","sort-alpha-down","sort-alpha-up","sort-numeric-down","sort-numeric-up","soundwave","speedometer2","square-half","stack","star-half","stars","stop-btn","stop-circle","suit-club","suit-diamond","suit-spade","sunglasses","sunrise","sunset","symmetry-horizontal","symmetry-vertical","tablet","tablet-landscape","telegram","telephone-forward","telephone-inbound","telephone-outbound","telephone-plus","telephone-x","text-center","text-indent-left","text-indent-right","text-left","text-right","thermometer-half","thermometer-high","thermometer-low","thermometer-snow","thermometer-sun","three-dots-vertical","toggle-off","toggle-on","toggle2-off","toggle2-on","tornado","translate","trash2","tree","truck-flatbed","tsunami","type","type-bold","type-h1","type-h2","type-h3","type-italic","type-strikethrough","type-underline","ui-checks","ui-checks-grid","ui-radios","ui-radios-grid","union","upc","upc-scan","view-list","view-stacked","vinyl","voicemail","volume-down","volume-mute","volume-off","volume-up","vr","wallet2","water","whatsapp","wifi-1","wifi-2","wifi-off","wind","window-dock","window-sidebar","x-circle","x-diamond","x-octagon","x-square","youtube"];globalThis.Component.register("IconPicker",e=>{e._thisObj=e,e.state=globalThis.NewState({value:"",search:"",open:!1}),e.addEventListener("bind",t=>{e.state.value=t.detail||""}),Object.defineProperty(e,"value",{get:()=>e.state.value,set:t=>{e.state.value=t||""}}),Object.defineProperty(e,"filteredIcons",{get:()=>{var t;const i=(null==(t=e.state.search)?void 0:t.toLowerCase())||"";return b.filter(e=>e.includes(i))}}),e.selectIcon=t=>{e.state.value=t,e.state.open=!1,e.dispatchEvent(new CustomEvent("change",{bubbles:!0,detail:t}))},e.toggle=()=>{e.state.open=!e.state.open,e.state.open&&setTimeout(()=>{var t;null==(t=globalThis.$(e,"input"))||t.focus()},10)};const t=t=>{e.contains(t.target)||(e.state.open=!1)};window.addEventListener("click",t),e.addEventListener("remove",()=>window.removeEventListener("click",t))},globalThis.Util.makeDom('\n\n
\n
\n
\n
\n
\n \n \n
No icons found
\n
\n
\n
\n'),globalThis.Util.makeDom("")),globalThis.AutoForm&&globalThis.AutoForm.register("IconPicker"),globalThis.Component.register("List",e=>{e.mode=e.getAttribute("mode")||"normal",e.fast=e.hasAttribute("fast"),e.collapsible=e.hasAttribute("collapsible");const t=e.fast?e.querySelector(".vs-pad-top"):null,i=e.fast?e.querySelector(".vs-pad-bottom"):null,a={idfield:"id",labelfield:"label",summaryfield:"summary",groupidfield:"id",grouplabelfield:"label",groupsummaryfield:"summary",groupfield:"group",parentfield:"parent",groupicon:"folder",itemicon:"file"};e.collapsed=globalThis.NewState({}),e.state.renderedList=[];const s=()=>{globalThis.Util.updateDefaults(e,a);const t=e.state.list||[],i=[];if("group"===e.mode){const a={};t.forEach(t=>{var i;return(a[i=t[e.groupfield]]??(a[i]=[])).push(t)}),(e.state.groups||[]).forEach(t=>{i.push({type:"group",...t});const s=a[t[e.groupidfield]];s&&s.forEach(e=>i.push({type:"item",...e}))})}else if("tree"===e.mode){const a={};t.forEach(t=>{var i;return(a[i=t[e.parentfield]||""]??(a[i]=[])).push(t)});const s=(t,l,n)=>t.forEach(t=>{var o;const r=t[e.idfield],d=!!(null==(o=a[r])?void 0:o.length),c=e.collapsed[r];i.push({type:"item",...t,_level:l,_hasChildren:d,_parents:n}),d&&!c&&s(a[r],l+1,[...n,r])});s(a[""]||[],0,[])}else t.forEach(e=>i.push({type:"item",...e}));e.state.flatList=i};e.state.__watch("list",s);const l=e.fast?globalThis.VirtualScroll():null;let n=!1;e.refresh=()=>{if(e.fast&&!n){n=!0;try{const a=l.calc(e,e.state.flatList);a&&(t&&(t.style.height=`${a.prevHeight}px`),i&&(i.style.height=`${a.postHeight}px`),e.state.listStartIndex=a.listStartIndex,e.state.renderedList=a.renderedList)}finally{setTimeout(()=>{n=!1},0)}}},e.onItemUpdate=(t,i)=>{e.fast&&l.update(t+(e.state.listStartIndex||0),i)},e.state.__watch("flatList",a=>{e.fast?(t&&(t.style.height="0px"),i&&(i.style.height="0px"),e.state.listStartIndex=0,e.state.renderedList=l.reset(a,e)||[],setTimeout(()=>{e.state.flatList===a&&l.init(a,e.refresh)})):e.state.renderedList=a}),e.selectItem=(t,i)=>{e.hasAttribute("auto-select")&&(e.state.selectedItem=e.state.selectedItem===t[e.idfield]?null:t[e.idfield]),e.dispatchEvent(new CustomEvent("itemclick",{bubbles:!1,detail:{item:t,index:i+(e.fast&&e.state.listStartIndex||0)}}))},e.selectGroup=(t,i)=>{e.hasAttribute("auto-select-group")&&(e.state.selectedGroup=e.state.selectedGroup===t[e.groupidfield]?null:t[e.groupidfield]),e.dispatchEvent(new CustomEvent("groupclick",{bubbles:!1,detail:{item:t,index:i}}))},e.toggleCollapse=t=>{e.collapsible&&t._hasChildren&&(e.collapsed[t[e.idfield]]=!e.collapsed[t[e.idfield]],s())},s()},globalThis.Util.makeDom('\n\n
\n
\n \n
\n \n \n \n \n \n \n \n
\n \n \n \n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n
\n')),globalThis.Component.register("Nav",e=>{e.vertical=e.hasAttribute("vertical"),e.click=(t,i)=>{t.noselect||i||(globalThis.Hash.nav=t.name),e.dispatchEvent(new CustomEvent("nav",{detail:{item:t},bubbles:!1}))}},globalThis.Util.makeDom('\n\n
\n
\n \n
\n \n \n
\n \n \n
\n
\n \n
\n \n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n
\n
\n \n
\n \n
\n')),globalThis.Component.register("Resizer",e=>{e.isVertical=e.hasAttribute("vertical");const t=parseInt(e.getAttribute("min"))||10,i=parseInt(e.getAttribute("max"))||1e3,a=e.target||e.previousElementSibling;e.addEventListener("bind",t=>{void 0!==t.detail&&null!==t.detail&&(a.style[e.isVertical?"height":"width"]=t.detail+"px")});const s=(a,s,l)=>{const n=a+(e.isVertical?l:s);return ni?i:n};e.addEventListener("mousedown",t=>{const i=e.isVertical?a.offsetHeight:a.offsetWidth;globalThis.MouseMover.start(t,{onmousemove:({w:t,h:l})=>{const n=s(i,t,l);a.style[e.isVertical?"height":"width"]=n+"px",e.dispatchEvent(new CustomEvent("resizing",{detail:{oldSize:i,newSize:n},bubbles:!1}))},onmouseup:({w:t,h:a})=>{const l=s(i,t,a);e.dispatchEvent(new CustomEvent("resize",{detail:{oldSize:i,newSize:l},bubbles:!1})),e.dispatchEvent(new CustomEvent("change",{detail:l,bubbles:!1}))}})})},globalThis.Util.makeDom("\n\n")),Object.defineProperty(e,"State",{enumerable:!0,get:()=>t.State}),e.APIComponent=p,e.AutoForm=o,e.HTTP=i,e.MouseMover=u,e.UI=a,e.VirtualScroll=r,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
diff --git a/src/API.js b/src/API.js
new file mode 100644
index 0000000..e417d37
--- /dev/null
+++ b/src/API.js
@@ -0,0 +1,44 @@
+/**
+ * API Component Module
+ */
+const APIComponent = globalThis.Component.register('API', container => {
+ container.request = globalThis.NewState({ url: '', method: 'GET', headers: {}, data: null, timeout: 10000, responseType: '' })
+ container.response = globalThis.NewState({ loading: false, ok: null, status: null, error: null, headers: {}, responseType: '', result: null })
+ container.result = globalThis.NewState()
+ container.do = (opt = {}) => {
+ return new Promise((resolve, reject) => {
+ const req = { ...container.request, ...opt }
+ if (!req.url) throw new Error('.url is required')
+ req.headers = { ...container.request.headers, ...opt.headers }
+ container.response.loading = true
+ globalThis.HTTP.request(req).then(resp => {
+ Object.keys(resp).forEach(k => { if (k !== 'result') container.response[k] = resp[k] })
+ if (resp.result && typeof resp.result === 'object' && container.result && typeof container.result === 'object') {
+ Object.assign(container.result, resp.result)
+ } else {
+ container.result = resp.result
+ }
+ container.response.loading = false
+ if (resp.ok === false) throw new Error(resp.error)
+ if (typeof resp.result === 'object' && resp.result.error) throw new Error(resp.result.error)
+ container.dispatchEvent(new CustomEvent('response', { detail: resp, bubbles: false }))
+ resolve(resp)
+ }).catch(err => {
+ if (!opt.noui && globalThis.UI?.toast) globalThis.UI.toast(err.message, { type: 'danger' })
+ container.dispatchEvent(new CustomEvent('error', { detail: err, bubbles: true }))
+ reject(err)
+ })
+ })
+ }
+ let _autoTimer = null
+ container.request.__watch(null, () => {
+ if (!container.hasAttribute('auto') || !container.request.url) return
+ if (_autoTimer) return
+ _autoTimer = Promise.resolve().then(() => {
+ container.do()
+ _autoTimer = null
+ })
+ })
+})
+
+export { APIComponent };
diff --git a/src/AutoForm.js b/src/AutoForm.js
new file mode 100644
index 0000000..a409913
--- /dev/null
+++ b/src/AutoForm.js
@@ -0,0 +1,136 @@
+/**
+ * AutoForm Core Module
+ */
+
+const AUTOFORM_BLUEPRINT = globalThis.Util.makeDom(/*html*/`
+
+`)
+
+const AUTOFORM_STYLE = globalThis.Util.makeDom(/*html*/``)
+
+globalThis.Component.register('AutoForm', container => {
+ if (!container.state.schema) container.state.schema = []
+
+ const ensureProxy = v => (v && typeof v === 'object' && !v.__isProxy) ? globalThis.NewState(v) : v;
+ container.state.__watch('data', v => container.data = ensureProxy(v));
+ container.data = ensureProxy(container.state.data || {});
+
+ container.vertical = container.hasAttribute('vertical')
+ container.horizontal = container.hasAttribute('horizontal')
+ container.inline = container.hasAttribute('inline')
+ container.nobutton = container.hasAttribute('nobutton')
+ container.request = { method: 'POST' }
+ container.response = {}
+ container.result = null
+
+ container.form = globalThis.$(container, 'form')
+ container.submit = (opt = {}) => {
+ if (!container.form.reportValidity()) return globalThis.UI?.toast?.('{#verify failed#}', { type: 'danger' })
+ if (!container.dispatchEvent(new CustomEvent('submit', { detail: container.data, cancelable: true, bubbles: false }))) return
+ const req = { ...container.request, data: container.data, noui: true, ...opt }
+ let task = null
+ if (container.api) task = container.api.do(req)
+ else if (container.request.url) task = globalThis.HTTP.request(req)
+ else return console.warn('{#please config .api or .request.url to auto submit#}')
+ task.then(resp => {
+ container.response = resp
+ container.result = resp.result
+ if (typeof resp.result === 'object' && resp.result.error) throw new Error(resp.result.error)
+ container.dispatchEvent(new CustomEvent('response', { detail: resp, bubbles: false }))
+ }).catch(err => {
+ if (globalThis.UI?.toast) globalThis.UI.toast(err.message, { type: 'danger' })
+ container.dispatchEvent(new CustomEvent('error', { detail: err, bubbles: true }))
+ })
+ }
+
+ container.checkIf = (item) => {
+ if (!item.if) return true
+ try {
+ const fn = new Function('Hash', 'LocalStorage', 'State', 'item', 'data', 'return ' + item.if)
+ return fn.call(container, globalThis.Hash, globalThis.LocalStorage, globalThis.State, item, container.data)
+ } catch (e) {
+ return false
+ }
+ }
+}, AUTOFORM_BLUEPRINT, AUTOFORM_STYLE)
+
+const findAnchorInBlueprint = (root) => {
+ let f = root.querySelector('[control-wrapper]');
+ if (f) return f;
+ for (const t of root.querySelectorAll('template')) {
+ f = findAnchorInBlueprint(t.content); if (f) return f;
+ }
+ return null;
+}
+
+const AutoForm = {
+ customTypes: [],
+ register: (name, typeName) => {
+ const type = typeName || name
+ if (!AutoForm.customTypes.find(t => t.name === name)) {
+ AutoForm.customTypes.push({ name, typeName: type })
+ AutoForm._addAutoFormComponent(name, type)
+ }
+ },
+ _addAutoFormComponent: (name, type) => {
+ const wrapper = findAnchorInBlueprint(AUTOFORM_BLUEPRINT)
+ if (wrapper) {
+ const node = globalThis.Util.makeDom(`<${name} $if="item.type?.toLowerCase() === '${type.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="this.data[item.name]" class="w-100">${name}>`)
+ wrapper.appendChild(node)
+ }
+ }
+}
+
+globalThis.AutoForm = AutoForm;
+export { AutoForm };
diff --git a/src/ColorPicker.js b/src/ColorPicker.js
new file mode 100644
index 0000000..1b350e9
--- /dev/null
+++ b/src/ColorPicker.js
@@ -0,0 +1,27 @@
+/**
+ * ColorPicker Component Module
+ */
+globalThis.Component.register('ColorPicker', container => {
+ container._thisObj = container;
+ container.state = globalThis.NewState({ value: '#000000' })
+ container.addEventListener('bind', e => {
+ container.state.value = e.detail || '#000000'
+ })
+ Object.defineProperty(container, 'value', {
+ get: () => container.state.value,
+ set: v => { container.state.value = v || '#000000'; }
+ })
+ container.updateValue = (val) => {
+ container.state.value = val
+ container.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: val }))
+ }
+}, globalThis.Util.makeDom(/*html*/`
+
+
+
+
+`))
+
+if (globalThis.AutoForm) {
+ globalThis.AutoForm.register('ColorPicker')
+}
diff --git a/src/DatePicker.js b/src/DatePicker.js
new file mode 100644
index 0000000..3715551
--- /dev/null
+++ b/src/DatePicker.js
@@ -0,0 +1,60 @@
+/**
+ * DatePicker Component Module
+ */
+globalThis.Component.register('DatePicker', container => {
+ container._thisObj = container;
+ container.state = globalThis.NewState({ start: '', end: '' })
+
+ container.addEventListener('bind', e => {
+ container.state.start = e.detail || ''
+ const form = container.closest('AutoForm')
+ const name = container.getAttribute('name')
+ const item = form?.state?.schema?.find(i => i.name === name)
+ const rangeEnd = item?.setting?.rangeEnd || container.rangeEnd
+ if (form && rangeEnd) {
+ container.state.end = form.data[rangeEnd] || ''
+ }
+ })
+
+ Object.defineProperty(container, 'isRange', {
+ get: () => {
+ const form = container.closest('AutoForm')
+ const name = container.getAttribute('name')
+ const item = form?.state?.schema?.find(i => i.name === name)
+ return !!(item?.setting?.rangeEnd || container.rangeEnd)
+ }
+ })
+
+ Object.defineProperty(container, 'value', {
+ get: () => container.state.start,
+ set: v => { container.state.start = v || ''; }
+ })
+
+ container.updateStart = (val) => {
+ container.state.start = val
+ container.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: val }))
+ }
+
+ container.updateEnd = (val) => {
+ container.state.end = val
+ const form = container.closest('AutoForm')
+ const name = container.getAttribute('name')
+ const item = form?.state?.schema?.find(i => i.name === name)
+ const rangeEnd = item?.setting?.rangeEnd || container.rangeEnd
+ if (form && rangeEnd) {
+ form.data[rangeEnd] = val
+ }
+ }
+}, globalThis.Util.makeDom(/*html*/`
+
+
+
+ -
+
+
+
+`))
+
+if (globalThis.AutoForm) {
+ globalThis.AutoForm.register('DatePicker')
+}
diff --git a/src/Dialog.js b/src/Dialog.js
new file mode 100644
index 0000000..461571d
--- /dev/null
+++ b/src/Dialog.js
@@ -0,0 +1,46 @@
+/**
+ * Dialog Component Module
+ */
+globalThis.Component.register('Dialog', globalThis.Component.getSetupFunction('Modal'), globalThis.Util.makeDom(/*html*/`
+
+`))
+
+let _dialogCount = 0
+globalThis.UI.showDialog = function ({ title = '', message = '', buttons = ['{#Close#}'], type = 'body' }) {
+ const d = document.body.appendChild(document.createElement('Dialog'))
+ d.style.zIndex = 2000 + ++_dialogCount
+ Promise.resolve().then(() => {
+ Object.assign(d.state, { message, title, type, buttons })
+ d.show()
+ })
+ return new Promise((resolve) => {
+ d.addEventListener('change', e => {
+ _dialogCount--
+ resolve(d.result || 0)
+ d.remove()
+ })
+ })
+}
+
+globalThis.UI.alert = function (message, options = {}) {
+ return globalThis.UI.showDialog({ message, ...options })
+}
+globalThis.UI.confirm = function (message, options = {}) {
+ return new Promise((resolve) => globalThis.UI.showDialog({ message, buttons: ['{#Cancel#}', '{#Confirm#}'], ...options }).then(index => resolve(index >= 2)).catch(() => resolve(false)))
+}
diff --git a/src/controls.js b/src/IconPicker.js
similarity index 70%
rename from src/controls.js
rename to src/IconPicker.js
index 4dba31f..3db9ec2 100644
--- a/src/controls.js
+++ b/src/IconPicker.js
@@ -1,128 +1,41 @@
-import { Component, NewState, Util, $ } from '@apigo.cc/state'
-import { AutoForm } from './form.js'
-
/**
- * DatePicker
- * 支持单日期及范围选择 (主字段 + 影子字段模式)
+ * IconPicker Component Module
*/
-Component.register('DatePicker', container => {
- container._thisObj = container;
- container.state = NewState({ start: '', end: '' })
-
- container.addEventListener('bind', e => {
- container.state.start = e.detail || ''
- const form = container.closest('AutoForm')
- const name = container.getAttribute('name')
- const item = form?.state?.schema?.find(i => i.name === name)
- const rangeEnd = item?.setting?.rangeEnd || container.rangeEnd
- if (form && rangeEnd) {
- container.state.end = form.data[rangeEnd] || ''
- }
- })
-
- Object.defineProperty(container, 'isRange', {
- get: () => {
- const form = container.closest('AutoForm')
- const name = container.getAttribute('name')
- const item = form?.state?.schema?.find(i => i.name === name)
- return !!(item?.setting?.rangeEnd || container.rangeEnd)
- }
- })
-
- Object.defineProperty(container, 'value', {
- get: () => container.state.start,
- set: v => { container.state.start = v || ''; }
- })
-
- container.updateStart = (val) => {
- container.state.start = val
- container.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: val }))
- }
-
- container.updateEnd = (val) => {
- container.state.end = val
- const form = container.closest('AutoForm')
- const name = container.getAttribute('name')
- const item = form?.state?.schema?.find(i => i.name === name)
- const rangeEnd = item?.setting?.rangeEnd || container.rangeEnd
- if (form && rangeEnd) {
- form.data[rangeEnd] = val
- }
- }
-}, Util.makeDom(/*html*/`
-
-
-
- -
-
-
-
-`))
-
-/**
- * ColorPicker
- * 支持颜色选择与十六进制文本输入
- */
-Component.register('ColorPicker', container => {
- container._thisObj = container;
- container.state = NewState({ value: '#000000' })
- container.addEventListener('bind', e => {
- container.state.value = e.detail || '#000000'
- })
- Object.defineProperty(container, 'value', {
- get: () => container.state.value,
- set: v => { container.state.value = v || '#000000'; }
- })
- container.updateValue = (val) => {
- container.state.value = val
- container.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: val }))
- }
-}, Util.makeDom(/*html*/`
-
-
-
-
-`))
-
const BOOTSTRAP_ICONS = ['alarm', 'archive', 'arrow-left', 'arrow-right', 'bag', 'bank', 'basket', 'bell', 'bookmark', 'box', 'briefcase', 'calendar', 'camera', 'cart', 'chat', 'check', 'chevron-down', 'chevron-left', 'chevron-right', 'chevron-up', 'clock', 'cloud', 'code', 'collection', 'command', 'cpu', 'credit-card', 'cup', 'dash', 'database', 'display', 'door-closed', 'download', 'droplet', 'earbuds', 'edit', 'egg', 'eject', 'envelope', 'eraser', 'eye', 'file', 'filter', 'flag', 'folder', 'gear', 'gem', 'gift', 'graph-up', 'grid', 'hammer', 'hand-thumbs-up', 'heart', 'house', 'image', 'inbox', 'info-circle', 'journal', 'key', 'laptop', 'layers', 'layout-text-sidebar-reverse', 'lightbulb', 'link', 'list', 'lock', 'map', 'mic', 'moon', 'mouse', 'music-note', 'newspaper', 'palette', 'paperclip', 'pause', 'pencil', 'person', 'phone', 'pie-chart', 'play', 'plus', 'printer', 'puzzle', 'question-circle', 'reception-4', 'record', 'reply', 'rss', 'save', 'search', 'send', 'server', 'share', 'shield', 'shop', 'shuffle', 'skip-end', 'skip-start', 'slash', 'sliders', 'smartphone', 'speaker', 'speedometer', 'spellcheck', 'square', 'star', 'stickies', 'stop', 'stopwatch', 'suit-heart', 'sun', 'table', 'tag', 'tags', 'telephone', 'terminal', 'text-paragraph', 'thermometer', 'three-dots', 'ticket', 'tools', 'trash', 'trophy', 'truck', 'tv', 'umbrella', 'unlock', 'upload', 'vector-pen', 'wallet', 'watch', 'wifi', 'window', 'wrench', 'x', 'zoom-in', 'zoom-out', 'activity', 'at', 'award', 'backspace', 'badge-3d', 'badge-4k', 'badge-8k', 'badge-ad', 'badge-ar', 'badge-cc', 'badge-hd', 'badge-tm', 'badge-vo', 'badge-vr', 'badge-wc', 'bar-chart', 'battery', 'bicycle', 'binoculars', 'blockquote-left', 'blockquote-right', 'book', 'bookshelf', 'bootstrap', 'border-all', 'border-bottom', 'border-center', 'border-inner', 'border-left', 'border-middle', 'border-outer', 'border-right', 'border-style', 'border-top', 'border-width', 'bounding-box', 'box-arrow-down', 'box-arrow-in-down', 'box-arrow-in-left', 'box-arrow-in-right', 'box-arrow-in-up', 'box-arrow-left', 'box-arrow-right', 'box-arrow-up', 'box-seam', 'brightness-alt-high', 'brightness-alt-low', 'brightness-high', 'brightness-low', 'broadcast', 'brush', 'bucket', 'bug', 'building', 'bullseye', 'calculator', 'calendar-check', 'calendar-date', 'calendar-day', 'calendar-event', 'calendar-minus', 'calendar-month', 'calendar-plus', 'calendar-range', 'calendar-week', 'calendar-x', 'calendar2', 'calendar3', 'calendar4', 'camera-reels', 'camera-video', 'capslock', 'card-checklist', 'card-heading', 'card-image', 'card-list', 'card-text', 'caret-down', 'caret-left', 'caret-right', 'caret-up', 'cart-check', 'cart-dash', 'cart-plus', 'cart-x', 'cash', 'cash-stack', 'cast', 'chat-dots', 'chat-left', 'chat-quote', 'chat-right', 'chat-square', 'chat-text', 'check-all', 'check-circle', 'check-square', 'circle', 'clipboard', 'cloud-arrow-down', 'cloud-arrow-up', 'cloud-check', 'cloud-download', 'cloud-fog', 'cloud-hail', 'cloud-lightning', 'cloud-minus', 'cloud-moon', 'cloud-plus', 'cloud-rain', 'cloud-slash', 'cloud-snow', 'cloud-sun', 'cloud-upload', 'clouds', 'cloudy', 'code-slash', 'code-square', 'collection-play', 'columns', 'columns-gap', 'compass', 'cone', 'cone-striped', 'controller', 'credit-card-2-back', 'credit-card-2-front', 'crop', 'cup-straw', 'cursor', 'dash-circle', 'dash-square', 'diagram-2', 'diagram-3', 'diamond', 'dice-1', 'dice-2', 'dice-3', 'dice-4', 'dice-5', 'dice-6', 'disc', 'discord', 'distribute-horizontal', 'distribute-vertical', 'door-open', 'dot', 'droplet-half', 'easel', 'egg-fried', 'emoji-angry', 'emoji-dizzy', 'emoji-expressionless', 'emoji-frown', 'emoji-heart-eyes', 'emoji-laughing', 'emoji-neutral', 'emoji-smile', 'emoji-sunglasses', 'emoji-wink', 'envelope-open', 'exclamation', 'exclamation-circle', 'exclamation-diamond', 'exclamation-octagon', 'exclamation-square', 'exclamation-triangle', 'eye-slash', 'eyedropper', 'facebook', 'file-arrow-down', 'file-arrow-up', 'file-binary', 'file-break', 'file-check', 'file-code', 'file-diff', 'file-earmark', 'file-excel', 'file-image', 'file-lock', 'file-medical', 'file-minus', 'file-music', 'file-pdf', 'file-person', 'file-play', 'file-plus', 'file-post', 'file-ppt', 'file-richtext', 'file-slides', 'file-spreadsheet', 'file-text', 'file-word', 'file-zip', 'files', 'film', 'filter-circle', 'filter-left', 'filter-right', 'filter-square', 'fingerprint', 'flower1', 'flower2', 'flower3', 'folder-check', 'folder-minus', 'folder-plus', 'folder-symlink', 'folder-x', 'folder2-open', 'fonts', 'forward', 'front', 'fullscreen', 'fullscreen-exit', 'funnel', 'gear-wide', 'gender-female', 'gender-male', 'gender-trans', 'geo', 'geo-alt', 'github', 'globe', 'google', 'graph-down', 'grid-1x2', 'grid-3x2', 'grid-3x3', 'grip-horizontal', 'grip-vertical', 'hand-index', 'hand-thumbs-down', 'handbag', 'hash', 'headphones', 'headset', 'heart-half', 'heptagon', 'hourglass', 'hourglass-bottom', 'hourglass-split', 'hourglass-top', 'house-door', 'hr', 'hurricane', 'image-alt', 'images', 'infinity', 'input-cursor', 'instagram', 'intersect', 'journal-album', 'journal-arrow-down', 'journal-arrow-up', 'journal-bookmark', 'journal-check', 'journal-code', 'journal-medical', 'journal-minus', 'journal-plus', 'journal-richtext', 'journal-text', 'journal-x', 'journals', 'justify', 'kanban', 'keyboard', 'ladder', 'lamp', 'layers-half', 'layout-sidebar', 'layout-split', 'layout-three-columns', 'life-preserver', 'lightbulb-off', 'lightning', 'lightning-charge', 'link-45deg', 'linkedin', 'list-check', 'list-nested', 'list-ol', 'list-stars', 'list-task', 'list-ul', 'mailbox', 'markdown', 'mask', 'mastodon', 'megaphone', 'menu-app', 'menu-button', 'messenger', 'mic-mute', 'minecart', 'minecart-loaded', 'moisture', 'mouse2', 'mouse3', 'music-note-beamed', 'music-note-list', 'music-player', 'node-minus', 'node-plus', 'nut', 'octagon', 'option', 'outlet', 'paint-bucket', 'patch-check', 'patch-exclamation', 'patch-minus', 'patch-plus', 'patch-question', 'pause-btn', 'pause-circle', 'peace', 'pen', 'pencil-square', 'pentagon', 'person-badge', 'person-bounding-box', 'person-circle', 'person-lines-fill', 'phone-landscape', 'phone-vibrate', 'pie-chart-fill', 'pin', 'pin-angle', 'pin-fill', 'pin-map', 'pip', 'play-btn', 'play-circle', 'plug', 'plus-circle', 'plus-square', 'power', 'question', 'question-diamond', 'question-square', 'rainbow', 'receipt', 'receipt-cutoff', 'reception-0', 'reception-1', 'reception-2', 'reception-3', 'record-btn', 'record-circle', 'record2', 'recycle', 'reddit', 'reply-all', 'router', 'rulers', 'safe', 'save2', 'sd-card', 'segmented-nav', 'shield-check', 'shield-exclamation', 'shield-lock', 'shield-shaded', 'shield-slash', 'shift', 'signpost', 'signpost-2', 'signpost-split', 'sim', 'skip-backward', 'skip-forward', 'slack', 'slash-circle', 'slash-square', 'smartwatch', 'snow', 'snow2', 'snow3', 'sort-alpha-down', 'sort-alpha-up', 'sort-numeric-down', 'sort-numeric-up', 'soundwave', 'speedometer2', 'square-half', 'stack', 'star-half', 'stars', 'stop-btn', 'stop-circle', 'suit-club', 'suit-diamond', 'suit-spade', 'sunglasses', 'sunrise', 'sunset', 'symmetry-horizontal', 'symmetry-vertical', 'tablet', 'tablet-landscape', 'telegram', 'telephone-forward', 'telephone-inbound', 'telephone-outbound', 'telephone-plus', 'telephone-x', 'text-center', 'text-indent-left', 'text-indent-right', 'text-left', 'text-right', 'thermometer-half', 'thermometer-high', 'thermometer-low', 'thermometer-snow', 'thermometer-sun', 'three-dots-vertical', 'toggle-off', 'toggle-on', 'toggle2-off', 'toggle2-on', 'tornado', 'translate', 'trash2', 'tree', 'truck-flatbed', 'tsunami', 'type', 'type-bold', 'type-h1', 'type-h2', 'type-h3', 'type-italic', 'type-strikethrough', 'type-underline', 'ui-checks', 'ui-checks-grid', 'ui-radios', 'ui-radios-grid', 'union', 'upc', 'upc-scan', 'view-list', 'view-stacked', 'vinyl', 'voicemail', 'volume-down', 'volume-mute', 'volume-off', 'volume-up', 'vr', 'wallet2', 'water', 'whatsapp', 'wifi-1', 'wifi-2', 'wifi-off', 'wind', 'window-dock', 'window-sidebar', 'x-circle', 'x-diamond', 'x-octagon', 'x-square', 'youtube']
-/**
- * IconPicker
- * 基于 Bootstrap Icons 的可视化选择控件
- */
-Component.register('IconPicker', container => {
+globalThis.Component.register('IconPicker', container => {
container._thisObj = container;
- container.state = NewState({ value: '', search: '', open: false })
- container.addEventListener('bind', e => {
- container.state.value = e.detail || ''
- })
-
- Object.defineProperty(container, 'value', {
- get: () => container.state.value,
- set: v => { container.state.value = v || ''; }
- })
+ container.state = globalThis.NewState({ value: '', search: '', open: false })
+ container.addEventListener('bind', e => {
+ container.state.value = e.detail || ''
+ })
- Object.defineProperty(container, 'filteredIcons', {
- get: () => {
- const s = container.state.search?.toLowerCase() || ''
- return BOOTSTRAP_ICONS.filter(i => i.includes(s))
- }
- })
+ Object.defineProperty(container, 'value', {
+ get: () => container.state.value,
+ set: v => { container.state.value = v || ''; }
+ })
- container.selectIcon = (icon) => {
- container.state.value = icon
- container.state.open = false
- container.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: icon }))
- }
+ Object.defineProperty(container, 'filteredIcons', {
+ get: () => {
+ const s = container.state.search?.toLowerCase() || ''
+ return BOOTSTRAP_ICONS.filter(i => i.includes(s))
+ }
+ })
- container.toggle = () => {
- container.state.open = !container.state.open
- if (container.state.open) {
- setTimeout(() => {
- $(container, 'input')?.focus()
- }, 10)
- }
- }
+ container.selectIcon = (icon) => {
+ container.state.value = icon
+ container.state.open = false
+ container.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: icon }))
+ }
+
+ container.toggle = () => {
+ container.state.open = !container.state.open
+ if (container.state.open) {
+ setTimeout(() => {
+ globalThis.$(container, 'input')?.focus()
+ }, 10)
+ }
+ }
const onGlobalClick = (e) => {
if (!container.contains(e.target)) {
@@ -131,7 +44,7 @@ Component.register('IconPicker', container => {
}
window.addEventListener('click', onGlobalClick)
container.addEventListener('remove', () => window.removeEventListener('click', onGlobalClick))
-}, Util.makeDom(/*html*/`
+}, globalThis.Util.makeDom(/*html*/`
-`), Util.makeDom(/*html*/``))
-// 注册到 AutoForm
-AutoForm.register('DatePicker')
-AutoForm.register('ColorPicker')
-AutoForm.register('IconPicker')
-
-export { }
+if (globalThis.AutoForm) {
+ globalThis.AutoForm.register('IconPicker')
+}
diff --git a/src/Modal.js b/src/Modal.js
new file mode 100644
index 0000000..0c9c39b
--- /dev/null
+++ b/src/Modal.js
@@ -0,0 +1,27 @@
+/**
+ * Modal Component Module
+ */
+globalThis.Component.register('Modal', container => {
+ container.modal = new bootstrap.Modal(container)
+ container.addEventListener('bind', e => {
+ e.detail ? container.modal.show() : container.modal.hide()
+ })
+ container.addEventListener('hide.bs.modal', () => {
+ document.activeElement?.blur()
+ container.dispatchEvent(new CustomEvent('change', { bubbles: false, detail: false }))
+ })
+ globalThis.Util.copyFunction(container, container.modal, 'show', 'hide')
+}, globalThis.Util.makeDom(/*html*/`
+
+`))
diff --git a/src/MouseMover.js b/src/MouseMover.js
new file mode 100644
index 0000000..e9c60f2
--- /dev/null
+++ b/src/MouseMover.js
@@ -0,0 +1,31 @@
+/**
+ * MouseMover Utility Module
+ */
+let _mouseMoverMoving = false
+let _mouseMoverPos = {}
+let _mouseMoverEvents = {}
+
+const MouseMover = {
+ start: (event, { onmousemove, onmouseup }) => {
+ _mouseMoverPos = { x: event.clientX, y: event.clientY, w: 0, h: 0 }
+ _mouseMoverEvents = { onmousemove, onmouseup }
+ _mouseMoverMoving = true
+ },
+}
+
+if (typeof document !== 'undefined') {
+ document.addEventListener('mouseup', event => {
+ if (!_mouseMoverMoving) return
+ _mouseMoverMoving = false
+ _mouseMoverEvents.onmouseup?.({ event, ..._mouseMoverPos })
+ })
+ document.addEventListener('mousemove', event => {
+ if (!_mouseMoverMoving) return
+ _mouseMoverPos.w = event.clientX - _mouseMoverPos.x
+ _mouseMoverPos.h = event.clientY - _mouseMoverPos.y
+ _mouseMoverEvents.onmousemove?.({ event, ..._mouseMoverPos })
+ })
+}
+
+globalThis.MouseMover = MouseMover;
+export { MouseMover };
diff --git a/src/Resizer.js b/src/Resizer.js
new file mode 100644
index 0000000..5b51bb9
--- /dev/null
+++ b/src/Resizer.js
@@ -0,0 +1,35 @@
+/**
+ * Resizer Component Module
+ */
+globalThis.Component.register('Resizer', container => {
+ container.isVertical = container.hasAttribute('vertical')
+ const min = parseInt(container.getAttribute('min')) || 10
+ const max = parseInt(container.getAttribute('max')) || 1000
+ const target = container.target || container.previousElementSibling
+ container.addEventListener('bind', e => {
+ if (e.detail !== undefined && e.detail !== null) {
+ target.style[container.isVertical ? 'height' : 'width'] = e.detail + 'px'
+ }
+ })
+ const getSize = (startSize, w, h) => {
+ const newSize = startSize + (container.isVertical ? h : w)
+ return newSize < min ? min : newSize > max ? max : newSize
+ }
+ container.addEventListener('mousedown', event => {
+ const startSize = container.isVertical ? target.offsetHeight : target.offsetWidth
+ globalThis.MouseMover.start(event, {
+ onmousemove: ({ w, h }) => {
+ const newSize = getSize(startSize, w, h)
+ target.style[container.isVertical ? 'height' : 'width'] = newSize + 'px'
+ container.dispatchEvent(new CustomEvent('resizing', { detail: { oldSize: startSize, newSize }, bubbles: false }))
+ },
+ onmouseup: ({ w, h }) => {
+ const newSize = getSize(startSize, w, h)
+ container.dispatchEvent(new CustomEvent('resize', { detail: { oldSize: startSize, newSize }, bubbles: false }))
+ container.dispatchEvent(new CustomEvent('change', { detail: newSize, bubbles: false }))
+ },
+ })
+ })
+}, globalThis.Util.makeDom(/*html*/`
+
+`))
diff --git a/src/TagsInput.js b/src/TagsInput.js
new file mode 100644
index 0000000..6ba8ac5
--- /dev/null
+++ b/src/TagsInput.js
@@ -0,0 +1,43 @@
+/**
+ * TagsInput Component Module
+ */
+globalThis.Component.register('TagsInput', container => {
+ container._thisObj = container;
+ container.addEventListener('bind', e => {
+ container.state.tags = Array.isArray(e.detail) ? e.detail : []
+ })
+}, globalThis.Util.makeDom(/*html*/`
+
+
+
+
+
+
+`), globalThis.Util.makeDom(/*html*/``))
+
+if (globalThis.AutoForm) {
+ globalThis.AutoForm.register('TagsInput')
+}
diff --git a/src/VirtualScroll.js b/src/VirtualScroll.js
new file mode 100644
index 0000000..7193e1d
--- /dev/null
+++ b/src/VirtualScroll.js
@@ -0,0 +1,100 @@
+/**
+ * VirtualScroll Utility Module
+ */
+const VirtualScroll = (options = {}) => {
+ const itemHeights = new Map()
+ const groupHeights = new Map()
+ let groupItemCount = 1
+ const avg = globalThis.Util.newAvg()
+ let padTop = 0, rowGap = 0, topMargin = 0, itemMarginTop = null, itemMarginBottom = null, listInited = false
+
+ const providedItemHeight = options.itemHeight || null;
+
+ return {
+ reset: (list, container) => {
+ listInited = false; itemHeights.clear(); groupHeights.clear(); avg.clear(); topMargin = 0; itemMarginTop = null; itemMarginBottom = null;
+ if (!list?.length) return [];
+ const size = list.length; groupItemCount = Math.ceil(Math.sqrt(size)) || 10;
+ const style = window.getComputedStyle(container);
+ padTop = parseFloat(style.paddingTop) || 0; rowGap = parseFloat(style.rowGap) || 0;
+ const visibleCount = Math.max(10, Math.ceil((container.clientHeight || 100) / (providedItemHeight || 32)));
+ return list.slice(0, Math.min(visibleCount * 3, size));
+ },
+ init: (list, refreshCallback) => {
+ if (listInited) return;
+ const size = list.length;
+ let defaultHeight = providedItemHeight || avg.get() || 32;
+ if (size > 0 && typeof list[0] === 'object' && list[0] !== null && list[0]._itemHeight) {
+ defaultHeight = list[0]._itemHeight;
+ }
+ avg.add(defaultHeight);
+ if (itemMarginTop === null) { itemMarginTop = 0; itemMarginBottom = 0; }
+ for (let i = 0; i < size; i++) {
+ if (!itemHeights.has(i)) {
+ const ih = (typeof list[i] === 'object' && list[i] !== null && list[i]._itemHeight) ? list[i]._itemHeight : defaultHeight;
+ itemHeights.set(i, ih);
+ }
+ }
+ for (let i = 0; i < size; i += groupItemCount) groupHeights.set(i, Math.min(groupItemCount, size - i) * defaultHeight);
+ listInited = true; refreshCallback();
+ },
+ update: (absoluteIndex, node) => {
+ if (node.offsetHeight === 0) return;
+ if (itemMarginTop === null) {
+ const style = window.getComputedStyle(node);
+ itemMarginTop = parseFloat(style.marginTop) || 0; itemMarginBottom = parseFloat(style.marginBottom) || 0;
+ }
+ if (absoluteIndex === 0 && !topMargin) topMargin = itemMarginTop;
+ const newHeight = node.offsetHeight + itemMarginTop + itemMarginBottom + rowGap;
+ const oldHeight = itemHeights.get(absoluteIndex);
+ if (newHeight !== oldHeight) {
+ itemHeights.set(absoluteIndex, newHeight); avg.add(newHeight);
+ const offset = newHeight - (oldHeight || 0), groupIndex = absoluteIndex - (absoluteIndex % groupItemCount);
+ if (groupHeights.has(groupIndex)) groupHeights.set(groupIndex, groupHeights.get(groupIndex) + offset);
+ }
+ },
+ calc: (container, list) => {
+ if (!listInited || !list) return null;
+ const size = list.length;
+ const avgVal = Math.max(16, avg.get() || 32);
+ let visibleCount = Math.max(10, Math.ceil((container.clientHeight || 100) / avgVal));
+ let prev = padTop + topMargin + rowGap, post = 0, status = 0, listStartIndex = 0, listEndIndex = 0;
+ let renderedList = [];
+ const scrollTop = container.scrollTop;
+ let loopCount = 0;
+
+ for (let i = 0; i < size; i++) {
+ if (++loopCount > size * 2) throw new Error('VirtualScroll infinite loop');
+ if (status === 0) {
+ const gh = groupHeights.get(i);
+ if (gh && prev + gh <= scrollTop && (i + groupItemCount < size)) {
+ prev += gh; i += groupItemCount - 1;
+ } else {
+ const ih = itemHeights.get(i);
+ if (prev + ih <= scrollTop && i < size - 1) {
+ prev += ih;
+ } else {
+ status = 1;
+ let visibleStartIndex = Math.max(0, i);
+ listStartIndex = Math.max(0, visibleStartIndex - visibleCount);
+ listEndIndex = Math.min(listStartIndex + visibleCount * 3, size);
+ i = listEndIndex - 1;
+ renderedList = list.slice(listStartIndex, listEndIndex);
+ for (let j = listStartIndex; j < visibleStartIndex; j++) prev -= itemHeights.get(j);
+ }
+ }
+ } else if (status === 1) {
+ const gh = groupHeights.get(i);
+ if (gh) { post += gh; i += groupItemCount - 1; }
+ else post += itemHeights.get(i);
+ }
+ }
+ const finalPrevHeight = Math.max(0, prev - padTop - topMargin - rowGap - (listStartIndex > 0 ? rowGap : 0));
+ const finalPostHeight = post > 0 ? Math.max(0, post - 2 * rowGap) : 0;
+ return { prevHeight: finalPrevHeight, postHeight: finalPostHeight, renderedList, listStartIndex };
+ }
+ }
+}
+
+globalThis.VirtualScroll = VirtualScroll;
+export { VirtualScroll };
diff --git a/src/form.js b/src/form.js
deleted file mode 100644
index 53278af..0000000
--- a/src/form.js
+++ /dev/null
@@ -1,178 +0,0 @@
-import { Component, NewState, Util, $, State } from '@apigo.cc/state'
-import { HTTP } from './http.js'
-
-/**
- * AutoForm 蓝图定义
- */
-const AUTOFORM_BLUEPRINT = Util.makeDom(/*html*/`
-
-`)
-
-const AUTOFORM_STYLE = Util.makeDom(/*html*/``)
-
-Component.register('AutoForm', container => {
- if (!container.state.schema) container.state.schema = []
-
- const ensureProxy = v => (v && typeof v === 'object' && !v.__isProxy) ? NewState(v) : v;
- container.state.__watch('data', v => container.data = ensureProxy(v));
- container.data = ensureProxy(container.state.data || {});
-
- container.vertical = container.hasAttribute('vertical')
- container.horizontal = container.hasAttribute('horizontal')
- container.inline = container.hasAttribute('inline')
- container.nobutton = container.hasAttribute('nobutton')
- container.request = { method: 'POST' }
- container.response = {}
- container.result = null
-
- container.form = $(container, 'form')
- container.submit = (opt = {}) => {
- if (!container.form.reportValidity()) return globalThis.UI?.toast?.('{#verify failed#}', { type: 'danger' })
- if (!container.dispatchEvent(new CustomEvent('submit', { detail: container.data, cancelable: true, bubbles: false }))) return
- const req = { ...container.request, data: container.data, noui: true, ...opt }
- let task = null
- if (container.api) task = container.api.do(req)
- else if (container.request.url) task = HTTP.request(req)
- else return console.warn('{#please config .api or .request.url to auto submit#}')
- task.then(resp => {
- container.response = resp
- container.result = resp.result
- if (typeof resp.result === 'object' && resp.result.error) throw new Error(resp.result.error)
- container.dispatchEvent(new CustomEvent('response', { detail: resp, bubbles: false }))
- }).catch(err => {
- if (globalThis.UI?.toast) UI.toast(err.message, { type: 'danger' })
- container.dispatchEvent(new CustomEvent('error', { detail: err, bubbles: true }))
- })
- }
-
- container.checkIf = (item) => {
- if (!item.if) return true
- try {
- const fn = new Function('Hash', 'LocalStorage', 'State', 'item', 'data', 'return ' + item.if)
- return fn.call(container, globalThis.Hash, globalThis.LocalStorage, globalThis.State, item, container.data)
- } catch (e) {
- return false
- }
- }
-}, AUTOFORM_BLUEPRINT, AUTOFORM_STYLE)
-
-const findAnchorInBlueprint = (root) => {
- let f = root.querySelector('[control-wrapper]');
- if (f) return f;
- for (const t of root.querySelectorAll('template')) {
- f = findAnchorInBlueprint(t.content); if (f) return f;
- }
- return null;
-}
-
-export const AutoForm = {
- customTypes: [],
- register: (name, typeName) => {
- const type = typeName || name
- if (!AutoForm.customTypes.find(t => t.name === name)) {
- AutoForm.customTypes.push({ name, typeName: type })
- AutoForm._addAutoFormComponent(name, type)
- }
- },
- _addAutoFormComponent: (name, type) => {
- const wrapper = findAnchorInBlueprint(AUTOFORM_BLUEPRINT)
- if (wrapper) {
- const node = Util.makeDom(`<${name} $if="item.type?.toLowerCase() === '${type.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="this.data[item.name]" class="w-100">${name}>`)
- wrapper.appendChild(node)
- }
- }
-}
-
-/**
- * TagsInput
- * 100% 还原 base_original.js 逻辑与写法
- */
-Component.register('TagsInput', container => {
- container._thisObj = container; // 夺回上下文主权
- container.addEventListener('bind', e => {
- container.state.tags = Array.isArray(e.detail) ? e.detail : []
- })
-}, Util.makeDom(/*html*/`
-
-
-
-
-
-
-`), Util.makeDom(/*html*/``))
-
-AutoForm.register('TagsInput')
diff --git a/src/http.js b/src/http.js
index b5a6b2d..b8c24f9 100644
--- a/src/http.js
+++ b/src/http.js
@@ -1,91 +1,54 @@
-import { Component, NewState } from '@apigo.cc/state'
-
-export const HTTP = {
- get: ({ url, ...opt }) => HTTP.request({ url, method: 'GET', ...opt }),
- post: ({ url, data, ...opt }) => HTTP.request({ url, method: 'POST', data, ...opt }),
- put: ({ url, data, ...opt }) => HTTP.request({ url, method: 'PUT', data, ...opt }),
- delete: ({ url, ...opt }) => HTTP.request({ url, method: 'DELETE', ...opt }),
- head: ({ url, ...opt }) => HTTP.request({ url, method: 'HEAD', ...opt }),
- request: async ({ url, method = 'POST', data = undefined, headers = {}, responseType, timeout = 10000 }) => {
- method = method.toUpperCase()
- const options = { method, signal: AbortSignal.timeout?.(timeout) }
- if (data !== undefined && method !== 'GET' && method !== 'HEAD') {
- if (data instanceof HTMLFormElement) data = new FormData(data)
- if (data && typeof data === 'object' && !(data instanceof FormData) && !(data instanceof ArrayBuffer || ArrayBuffer.isView(data)) && Object.values(data).some(v => v instanceof File || v instanceof Blob || v instanceof FileList || (Array.isArray(v) && v.some(i => i instanceof File || i instanceof Blob)))) {
- const fd = new FormData()
- for (const [k, v] of Object.entries(data)) {
- if (v instanceof FileList || Array.isArray(v)) Array.from(v).forEach(item => fd.append(k, item))
- else if (v !== undefined && v !== null) fd.append(k, v)
- }
- data = fd
- }
- if (data instanceof FormData) {
- delete headers['Content-Type']
- } else if (typeof data !== 'string' && !(data instanceof ArrayBuffer || ArrayBuffer.isView(data))) {
- data = JSON.stringify(data)
- if (!headers['Content-Type']) headers['Content-Type'] = 'application/json'
- }
- options.body = data
- }
- if (Object.keys(headers).length) options.headers = headers
- const response = { error: null, ok: null, status: 0, headers: {}, responseType: '', result: null }
- try {
- const resp = await fetch(url, options)
- Object.assign(response, { ok: resp.ok, status: resp.status, headers: Object.fromEntries(resp.headers.entries()) })
- if (!responseType) {
- const contentType = resp.headers.get('Content-Type') || ''
- if (contentType.includes('application/json')) responseType = 'json'
- else if (/image|video|audio|pdf|zip|octet-stream/.test(contentType)) responseType = 'binary'
- else responseType = 'text'
- response.responseType = responseType
- }
- if (response.ok === false) response.error = (response.statusText || 'HTTP ' + response.status + ' error') + ' for ' + url
- if (responseType === 'json') response.result = await resp.json()
- else response.result = (responseType === 'binary') ? await resp.arrayBuffer() : await resp.text()
- } catch (err) {
- Object.assign(response, { error: err.message || String(err), ok: false })
- }
- return response
- }
+/**
+ * HTTP Module
+ */
+const HTTP = {
+ get: ({ url, ...opt }) => HTTP.request({ url, method: 'GET', ...opt }),
+ post: ({ url, data, ...opt }) => HTTP.request({ url, method: 'POST', data, ...opt }),
+ put: ({ url, data, ...opt }) => HTTP.request({ url, method: 'PUT', data, ...opt }),
+ delete: ({ url, ...opt }) => HTTP.request({ url, method: 'DELETE', ...opt }),
+ head: ({ url, ...opt }) => HTTP.request({ url, method: 'HEAD', ...opt }),
+ request: async ({ url, method = 'POST', data = undefined, headers = {}, responseType, timeout = 10000 }) => {
+ method = method.toUpperCase()
+ const options = { method, signal: AbortSignal.timeout?.(timeout) }
+ if (data !== undefined && method !== 'GET' && method !== 'HEAD') {
+ if (data instanceof HTMLFormElement) data = new FormData(data)
+ if (data && typeof data === 'object' && !(data instanceof FormData) && !(data instanceof ArrayBuffer || ArrayBuffer.isView(data)) && Object.values(data).some(v => v instanceof File || v instanceof Blob || v instanceof FileList || (Array.isArray(v) && v.some(i => i instanceof File || i instanceof Blob)))) {
+ const fd = new FormData()
+ for (const [k, v] of Object.entries(data)) {
+ if (v instanceof FileList || Array.isArray(v)) Array.from(v).forEach(item => fd.append(k, item))
+ else if (v !== undefined && v !== null) fd.append(k, v)
+ }
+ data = fd
+ }
+ if (data instanceof FormData) {
+ delete headers['Content-Type']
+ } else if (typeof data !== 'string' && !(data instanceof ArrayBuffer || ArrayBuffer.isView(data))) {
+ data = JSON.stringify(data)
+ if (!headers['Content-Type']) headers['Content-Type'] = 'application/json'
+ }
+ options.body = data
+ }
+ if (Object.keys(headers).length) options.headers = headers
+ const response = { error: null, ok: null, status: 0, headers: {}, responseType: '', result: null }
+ try {
+ const resp = await fetch(url, options)
+ Object.assign(response, { ok: resp.ok, status: resp.status, headers: Object.fromEntries(resp.headers.entries()) })
+ if (!responseType) {
+ const contentType = resp.headers.get('Content-Type') || ''
+ if (contentType.includes('application/json')) responseType = 'json'
+ else if (/image|video|audio|pdf|zip|octet-stream/.test(contentType)) responseType = 'binary'
+ else responseType = 'text'
+ response.responseType = responseType
+ }
+ if (response.ok === false) response.error = (response.statusText || 'HTTP ' + response.status + ' error') + ' for ' + url
+ if (responseType === 'json') response.result = await resp.json()
+ else response.result = (responseType === 'binary') ? await resp.arrayBuffer() : await resp.text()
+ } catch (err) {
+ Object.assign(response, { error: err.message || String(err), ok: false })
+ }
+ return response
+ }
}
-// HTTP 和 API 组件
-export const APIComponent = Component.register('API', container => {
- container.request = NewState({ url: '', method: 'GET', headers: {}, data: null, timeout: 10000, responseType: '' })
- container.response = NewState({ loading: false, ok: null, status: null, error: null, headers: {}, responseType: '', result: null })
- container.result = NewState()
- container.do = (opt = {}) => {
- return new Promise((resolve, reject) => {
- const req = { ...container.request, ...opt }
- if (!req.url) throw new Error('.url is required')
- req.headers = { ...container.request.headers, ...opt.headers }
- container.response.loading = true
- HTTP.request(req).then(resp => {
- Object.keys(resp).forEach(k => { if (k !== 'result') container.response[k] = resp[k] })
- if (resp.result && typeof resp.result === 'object' && container.result && typeof container.result === 'object') {
- Object.assign(container.result, resp.result)
- } else {
- container.result = resp.result
- }
- container.response.loading = false
- if (resp.ok === false) throw new Error(resp.error)
- if (typeof resp.result === 'object' && resp.result.error) throw new Error(resp.result.error)
- container.dispatchEvent(new CustomEvent('response', { detail: resp, bubbles: false }))
- resolve(resp)
- }).catch(err => {
- if (!opt.noui && globalThis.UI?.toast) UI.toast(err.message, { type: 'danger' })
- container.dispatchEvent(new CustomEvent('error', { detail: err, bubbles: true }))
- reject(err)
- })
- })
- }
- let _autoTimer = null
- container.request.__watch(null, () => {
- if (!container.hasAttribute('auto') || !container.request.url) return
- if (_autoTimer) return
- _autoTimer = Promise.resolve().then(() => {
- container.do()
- _autoTimer = null
- })
- })
-})
+globalThis.HTTP = HTTP;
+export { HTTP };
diff --git a/src/index.js b/src/index.js
index 8c337d5..d844b90 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,49 +1,34 @@
-import { NewState, State } from '@apigo.cc/state'
-import '@apigo.cc/bootstrap'
+/**
+ * Base Project Entry Point
+ * Orchestrates component loading and re-exports public APIs.
+ */
-// Re-exports
-export * from './http.js'
-export * from './ui.js'
-export * from './form.js'
-export * from './controls.js'
-export * from './list.js'
-export * from './nav.js'
-export * from './interaction.js'
+// Core Framework & State (Must be loaded first if not already global)
+export { State } from '@apigo.cc/state';
-export { State }
+// 1. Foundation Objects
+import './HTTP.js';
+import './UI.js';
+import './AutoForm.js';
+import './VirtualScroll.js';
+import './MouseMover.js';
-if (typeof window !== 'undefined') {
- window.addEventListener('beforeunload', (event) => {
- if (State.exitBlocks > 0) event.preventDefault()
- })
-}
-
-const htmlNode = document.documentElement;
-if (!htmlNode.hasAttribute('$data-bs-theme') && !htmlNode.hasAttribute('data-bs-theme')) {
- htmlNode.setAttribute('$data-bs-theme', "LocalStorage.darkMode?'dark':'light'");
-}
-
-// Side effects: ensure global namespaces are populated
-import { HTTP } from './http.js'
-import { UI } from './ui.js'
-import { AutoForm } from './form.js'
-import { MouseMover } from './interaction.js'
-import { VirtualScroll } from './list.js'
-import './nav.js'
-import './controls.js'
-
-globalThis.HTTP = HTTP
-globalThis.UI = UI
-globalThis.AutoForm = AutoForm
-globalThis.MouseMover = MouseMover
-globalThis.VirtualScroll = VirtualScroll
-
-const ApigoBase = {
- HTTP, UI, AutoForm, MouseMover, VirtualScroll, State,
- List: VirtualScroll
-};
-
-if (typeof document !== 'undefined') {
- globalThis.ApigoBase = ApigoBase;
-}
+// 2. Components (Order matters for some)
+import './API.js';
+import './Modal.js';
+import './Dialog.js';
+import './TagsInput.js';
+import './DatePicker.js';
+import './ColorPicker.js';
+import './IconPicker.js';
+import './List.js';
+import './Nav.js';
+import './Resizer.js';
+// Re-exports for ESM compatibility
+export { HTTP } from './HTTP.js';
+export { UI } from './UI.js';
+export { AutoForm } from './AutoForm.js';
+export { VirtualScroll } from './VirtualScroll.js';
+export { MouseMover } from './MouseMover.js';
+export { APIComponent } from './API.js';
diff --git a/src/interaction.js b/src/interaction.js
deleted file mode 100644
index 363e6e7..0000000
--- a/src/interaction.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import { Component, Util } from '@apigo.cc/state'
-
-let _mouseMoverMoving = false
-let _mouseMoverPos = {}
-let _mouseMoverEvents = {}
-
-export const MouseMover = {
- start: (event, { onmousemove, onmouseup }) => {
- _mouseMoverPos = { x: event.clientX, y: event.clientY, w: 0, h: 0 }
- _mouseMoverEvents = { onmousemove, onmouseup }
- _mouseMoverMoving = true
- },
-}
-
-if (typeof document !== 'undefined') {
- document.addEventListener('mouseup', event => {
- if (!_mouseMoverMoving) return
- _mouseMoverMoving = false
- _mouseMoverEvents.onmouseup?.({ event, ..._mouseMoverPos })
- })
- document.addEventListener('mousemove', event => {
- if (!_mouseMoverMoving) return
- _mouseMoverPos.w = event.clientX - _mouseMoverPos.x
- _mouseMoverPos.h = event.clientY - _mouseMoverPos.y
- _mouseMoverEvents.onmousemove?.({ event, ..._mouseMoverPos })
- })
-}
-
-Component.register('Resizer', container => {
- container.isVertical = container.hasAttribute('vertical')
- const min = parseInt(container.getAttribute('min')) || 10
- const max = parseInt(container.getAttribute('max')) || 1000
- const target = container.target || container.previousElementSibling
- container.addEventListener('bind', e => {
- if (e.detail !== undefined && e.detail !== null) {
- target.style[container.isVertical ? 'height' : 'width'] = e.detail + 'px'
- }
- })
- const getSize = (startSize, w, h) => {
- const newSize = startSize + (container.isVertical ? h : w)
- return newSize < min ? min : newSize > max ? max : newSize
- }
- container.addEventListener('mousedown', event => {
- const startSize = container.isVertical ? target.offsetHeight : target.offsetWidth
- MouseMover.start(event, {
- onmousemove: ({ w, h }) => {
- const newSize = getSize(startSize, w, h)
- target.style[container.isVertical ? 'height' : 'width'] = newSize + 'px'
- container.dispatchEvent(new CustomEvent('resizing', { detail: { oldSize: startSize, newSize }, bubbles: false }))
- },
- onmouseup: ({ w, h }) => {
- const newSize = getSize(startSize, w, h)
- container.dispatchEvent(new CustomEvent('resize', { detail: { oldSize: startSize, newSize }, bubbles: false }))
- container.dispatchEvent(new CustomEvent('change', { detail: newSize, bubbles: false }))
- },
- })
- })
-}, Util.makeDom(/*html*/`
-
-`))
diff --git a/src/list.js b/src/list.js
index a8d1a29..ae52c8e 100644
--- a/src/list.js
+++ b/src/list.js
@@ -1,217 +1,123 @@
-import { Component, NewState, Util, Hash } from '@apigo.cc/state'
+/**
+ * List Component Module
+ */
+globalThis.Component.register('List', container => {
+ container.mode = container.getAttribute('mode') || 'normal'
+ container.fast = container.hasAttribute('fast')
+ container.collapsible = container.hasAttribute('collapsible')
-export const VirtualScroll = (options = {}) => {
- const itemHeights = new Map()
- const groupHeights = new Map()
- let groupItemCount = 1
- const avg = Util.newAvg()
- let padTop = 0, rowGap = 0, topMargin = 0, itemMarginTop = null, itemMarginBottom = null, listInited = false
+ const padTopEl = container.fast ? container.querySelector('.vs-pad-top') : null
+ const padBottomEl = container.fast ? container.querySelector('.vs-pad-bottom') : null
- const providedItemHeight = options.itemHeight || null;
+ const defaultSets = {
+ idfield: 'id', labelfield: 'label', summaryfield: 'summary',
+ groupidfield: 'id', grouplabelfield: 'label', groupsummaryfield: 'summary', groupfield: 'group',
+ parentfield: 'parent', groupicon: 'folder', itemicon: 'file'
+ }
+ container.collapsed = globalThis.NewState({})
+ container.state.renderedList = []
- return {
- reset: (list, container) => {
- listInited = false; itemHeights.clear(); groupHeights.clear(); avg.clear(); topMargin = 0; itemMarginTop = null; itemMarginBottom = null;
- if (!list?.length) return [];
- const size = list.length; groupItemCount = Math.ceil(Math.sqrt(size)) || 10;
- const style = window.getComputedStyle(container);
- padTop = parseFloat(style.paddingTop) || 0; rowGap = parseFloat(style.rowGap) || 0;
- const visibleCount = Math.max(10, Math.ceil((container.clientHeight || 100) / (providedItemHeight || 32)));
- return list.slice(0, Math.min(visibleCount * 3, size));
- },
- init: (list, refreshCallback) => {
- if (listInited) return;
- const size = list.length;
- let defaultHeight = providedItemHeight || avg.get() || 32;
- if (size > 0 && typeof list[0] === 'object' && list[0] !== null && list[0]._itemHeight) {
- defaultHeight = list[0]._itemHeight;
- }
- avg.add(defaultHeight);
- if (itemMarginTop === null) { itemMarginTop = 0; itemMarginBottom = 0; }
- for (let i = 0; i < size; i++) {
- if (!itemHeights.has(i)) {
- const ih = (typeof list[i] === 'object' && list[i] !== null && list[i]._itemHeight) ? list[i]._itemHeight : defaultHeight;
- itemHeights.set(i, ih);
- }
- }
- for (let i = 0; i < size; i += groupItemCount) groupHeights.set(i, Math.min(groupItemCount, size - i) * defaultHeight);
- listInited = true; refreshCallback();
- },
- update: (absoluteIndex, node) => {
- if (node.offsetHeight === 0) return;
- if (itemMarginTop === null) {
- const style = window.getComputedStyle(node);
- itemMarginTop = parseFloat(style.marginTop) || 0; itemMarginBottom = parseFloat(style.marginBottom) || 0;
- }
- if (absoluteIndex === 0 && !topMargin) topMargin = itemMarginTop;
- const newHeight = node.offsetHeight + itemMarginTop + itemMarginBottom + rowGap;
- const oldHeight = itemHeights.get(absoluteIndex);
- if (newHeight !== oldHeight) {
- itemHeights.set(absoluteIndex, newHeight); avg.add(newHeight);
- const offset = newHeight - (oldHeight || 0), groupIndex = absoluteIndex - (absoluteIndex % groupItemCount);
- if (groupHeights.has(groupIndex)) groupHeights.set(groupIndex, groupHeights.get(groupIndex) + offset);
- }
- },
- calc: (container, list) => {
- if (!listInited || !list) return null;
- const size = list.length;
- const avgVal = Math.max(16, avg.get() || 32);
- let visibleCount = Math.max(10, Math.ceil((container.clientHeight || 100) / avgVal));
- let prev = padTop + topMargin + rowGap, post = 0, status = 0, listStartIndex = 0, listEndIndex = 0;
- let renderedList = [];
- const scrollTop = container.scrollTop;
- let loopCount = 0;
+ const updateFlatList = () => {
+ globalThis.Util.updateDefaults(container, defaultSets)
+ const list = container.state.list || [], flatList = []
+ if (container.mode === 'group') {
+ const itemMap = {}
+ list.forEach(item => (itemMap[item[container.groupfield]] ??= []).push(item));
+ (container.state.groups || []).forEach(group => {
+ flatList.push({ type: 'group', ...group })
+ const items = itemMap[group[container.groupidfield]]
+ if (items) items.forEach(item => flatList.push({ type: 'item', ...item }))
+ })
+ } else if (container.mode === 'tree') {
+ const childrenMap = {}
+ list.forEach(item => (childrenMap[item[container.parentfield] || ''] ??= []).push(item))
+ const traverse = (items, level, parents) => items.forEach(item => {
+ const id = item[container.idfield], hasChildren = !!childrenMap[id]?.length
+ const isCollapsed = container.collapsed[id]
+ flatList.push({ type: 'item', ...item, _level: level, _hasChildren: hasChildren, _parents: parents })
+ if (hasChildren && !isCollapsed) traverse(childrenMap[id], level + 1, [...parents, id])
+ })
+ traverse(childrenMap[''] || [], 0, [])
+ } else list.forEach(item => flatList.push({ type: 'item', ...item }))
+ container.state.flatList = flatList
+ }
- for (let i = 0; i < size; i++) {
- if (++loopCount > size * 2) throw new Error('VirtualScroll infinite loop');
- if (status === 0) {
- const gh = groupHeights.get(i);
- if (gh && prev + gh <= scrollTop && (i + groupItemCount < size)) {
- prev += gh; i += groupItemCount - 1;
- } else {
- const ih = itemHeights.get(i);
- if (prev + ih <= scrollTop && i < size - 1) {
- prev += ih;
- } else {
- status = 1;
- let visibleStartIndex = Math.max(0, i);
- listStartIndex = Math.max(0, visibleStartIndex - visibleCount);
- listEndIndex = Math.min(listStartIndex + visibleCount * 3, size);
- i = listEndIndex - 1;
- renderedList = list.slice(listStartIndex, listEndIndex);
- for (let j = listStartIndex; j < visibleStartIndex; j++) prev -= itemHeights.get(j);
- }
- }
- } else if (status === 1) {
- const gh = groupHeights.get(i);
- if (gh) { post += gh; i += groupItemCount - 1; }
- else post += itemHeights.get(i);
- }
- }
- const finalPrevHeight = Math.max(0, prev - padTop - topMargin - rowGap - (listStartIndex > 0 ? rowGap : 0));
- const finalPostHeight = post > 0 ? Math.max(0, post - 2 * rowGap) : 0;
- return { prevHeight: finalPrevHeight, postHeight: finalPostHeight, renderedList, listStartIndex };
- }
- }
-}
+ container.state.__watch('list', updateFlatList)
+ const vs = container.fast ? globalThis.VirtualScroll() : null
-Component.register('List', container => {
- container.mode = container.getAttribute('mode') || 'normal'
- container.fast = container.hasAttribute('fast')
- container.collapsible = container.hasAttribute('collapsible')
-
- const padTopEl = container.fast ? container.querySelector('.vs-pad-top') : null
- const padBottomEl = container.fast ? container.querySelector('.vs-pad-bottom') : null
+ let refreshing = false
+ container.refresh = () => {
+ if (!container.fast || refreshing) return
+ refreshing = true
+ try {
+ const res = vs.calc(container, container.state.flatList)
+ if (res) {
+ if (padTopEl) padTopEl.style.height = `${res.prevHeight}px`
+ if (padBottomEl) padBottomEl.style.height = `${res.postHeight}px`
+ container.state.listStartIndex = res.listStartIndex
+ container.state.renderedList = res.renderedList
+ }
+ } finally {
+ setTimeout(() => { refreshing = false }, 0)
+ }
+ }
- const defaultSets = {
- idfield: 'id', labelfield: 'label', summaryfield: 'summary',
- groupidfield: 'id', grouplabelfield: 'label', groupsummaryfield: 'summary', groupfield: 'group',
- parentfield: 'parent', groupicon: 'folder', itemicon: 'file'
- }
- container.collapsed = NewState({})
- container.state.renderedList = []
+ container.onItemUpdate = (index, node) => { if (container.fast) vs.update(index + (container.state.listStartIndex || 0), node) }
- const updateFlatList = () => {
- Util.updateDefaults(container, defaultSets)
- const list = container.state.list || [], flatList = []
- if (container.mode === 'group') {
- const itemMap = {}
- list.forEach(item => (itemMap[item[container.groupfield]] ??= []).push(item));
- (container.state.groups || []).forEach(group => {
- flatList.push({ type: 'group', ...group })
- const items = itemMap[group[container.groupidfield]]
- if (items) items.forEach(item => flatList.push({ type: 'item', ...item }))
- })
- } else if (container.mode === 'tree') {
- const childrenMap = {}
- list.forEach(item => (childrenMap[item[container.parentfield] || ''] ??= []).push(item))
- const traverse = (items, level, parents) => items.forEach(item => {
- const id = item[container.idfield], hasChildren = !!childrenMap[id]?.length
- const isCollapsed = container.collapsed[id]
- flatList.push({ type: 'item', ...item, _level: level, _hasChildren: hasChildren, _parents: parents })
- if (hasChildren && !isCollapsed) traverse(childrenMap[id], level + 1, [...parents, id])
- })
- traverse(childrenMap[''] || [], 0, [])
- } else list.forEach(item => flatList.push({ type: 'item', ...item }))
- container.state.flatList = flatList
- }
-
- container.state.__watch('list', updateFlatList)
- const vs = container.fast ? VirtualScroll() : null
+ container.state.__watch('flatList', flatList => {
+ if (container.fast) {
+ if (padTopEl) padTopEl.style.height = '0px'
+ if (padBottomEl) padBottomEl.style.height = '0px'
+ container.state.listStartIndex = 0
+ container.state.renderedList = vs.reset(flatList, container) || []
+ setTimeout(() => { if (container.state.flatList === flatList) vs.init(flatList, container.refresh) })
+ } else container.state.renderedList = flatList
+ })
- let refreshing = false
- container.refresh = () => {
- if (!container.fast || refreshing) return
- refreshing = true
- try {
- const res = vs.calc(container, container.state.flatList)
- if (res) {
- if (padTopEl) padTopEl.style.height = `${res.prevHeight}px`
- if (padBottomEl) padBottomEl.style.height = `${res.postHeight}px`
- container.state.listStartIndex = res.listStartIndex
- container.state.renderedList = res.renderedList
- }
- } finally {
- setTimeout(() => { refreshing = false }, 0)
- }
- }
+ container.selectItem = (item, index) => {
+ if (container.hasAttribute('auto-select')) container.state.selectedItem = container.state.selectedItem === item[container.idfield] ? null : item[container.idfield]
+ container.dispatchEvent(new CustomEvent('itemclick', { bubbles: false, detail: { item, index: index + (container.fast ? (container.state.listStartIndex || 0) : 0) } }))
+ }
+ container.selectGroup = (item, index) => {
+ if (container.hasAttribute('auto-select-group')) container.state.selectedGroup = container.state.selectedGroup === item[container.groupidfield] ? null : item[container.groupidfield]
+ container.dispatchEvent(new CustomEvent('groupclick', { bubbles: false, detail: { item, index } }))
+ }
+ container.toggleCollapse = (item) => { if (container.collapsible && item._hasChildren) { container.collapsed[item[container.idfield]] = !container.collapsed[item[container.idfield]]; updateFlatList(); } }
- container.onItemUpdate = (index, node) => { if (container.fast) vs.update(index + (container.state.listStartIndex || 0), node) }
-
- container.state.__watch('flatList', flatList => {
- if (container.fast) {
- if (padTopEl) padTopEl.style.height = '0px'
- if (padBottomEl) padBottomEl.style.height = '0px'
- container.state.listStartIndex = 0
- container.state.renderedList = vs.reset(flatList, container) || []
- setTimeout(() => { if (container.state.flatList === flatList) vs.init(flatList, container.refresh) })
- } else container.state.renderedList = flatList
- })
-
- container.selectItem = (item, index) => {
- if (container.hasAttribute('auto-select')) container.state.selectedItem = container.state.selectedItem === item[container.idfield] ? null : item[container.idfield]
- container.dispatchEvent(new CustomEvent('itemclick', { bubbles: false, detail: { item, index: index + (container.fast ? (container.state.listStartIndex || 0) : 0) } }))
- }
- container.selectGroup = (item, index) => {
- if (container.hasAttribute('auto-select-group')) container.state.selectedGroup = container.state.selectedGroup === item[container.groupidfield] ? null : item[container.groupidfield]
- container.dispatchEvent(new CustomEvent('groupclick', { bubbles: false, detail: { item, index } }))
- }
- container.toggleCollapse = (item) => { if (container.collapsible && item._hasChildren) { container.collapsed[item[container.idfield]] = !container.collapsed[item[container.idfield]]; updateFlatList(); } }
-
- updateFlatList()
-}, Util.makeDom(/*html*/`
+ updateFlatList()
+}, globalThis.Util.makeDom(/*html*/`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`))
diff --git a/src/nav.js b/src/nav.js
index 377e0a1..dd2ab2a 100644
--- a/src/nav.js
+++ b/src/nav.js
@@ -1,53 +1,54 @@
-import { Component, Hash, Util } from '@apigo.cc/state'
-
-Component.register('Nav', container => {
- container.vertical = container.hasAttribute('vertical')
- container.click = (item, noselect) => {
- if (!item.noselect && !noselect) Hash.nav = item.name
- container.dispatchEvent(new CustomEvent('nav', { detail: { item }, bubbles: false }))
- }
-}, Util.makeDom(/*html*/`
+/**
+ * Nav Component Module
+ */
+globalThis.Component.register('Nav', container => {
+ container.vertical = container.hasAttribute('vertical')
+ container.click = (item, noselect) => {
+ if (!item.noselect && !noselect) globalThis.Hash.nav = item.name
+ container.dispatchEvent(new CustomEvent('nav', { detail: { item }, bubbles: false }))
+ }
+}, globalThis.Util.makeDom(/*html*/`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`))
diff --git a/src/ui.js b/src/ui.js
index 30402e2..6cc3b77 100644
--- a/src/ui.js
+++ b/src/ui.js
@@ -1,92 +1,26 @@
-import { Component, Util, $ } from '@apigo.cc/state'
+/**
+ * UI Module
+ */
+const UI = {}
-export const UI = {}
-
-Component.register('Modal', container => {
- container.modal = new bootstrap.Modal(container)
- container.addEventListener('bind', e => {
- e.detail ? container.modal.show() : container.modal.hide()
- })
- container.addEventListener('hide.bs.modal', () => {
- document.activeElement?.blur()
- container.dispatchEvent(new CustomEvent('change', { bubbles: false, detail: false }))
- })
- Util.copyFunction(container, container.modal, 'show', 'hide')
-}, Util.makeDom(/*html*/`
-
-`))
-
-Component.register('Dialog', Component.getSetupFunction('Modal'), Util.makeDom(/*html*/`
-
-`))
-
-let _dialogCount = 0
-UI.showDialog = function ({ title = '', message = '', buttons = ['{#Close#}'], type = 'body' }) {
- const d = document.body.appendChild(document.createElement('Dialog'))
- d.style.zIndex = 2000 + ++_dialogCount
- Promise.resolve().then(() => {
- Object.assign(d.state, { message, title, type, buttons })
- d.show()
- })
- return new Promise((resolve) => {
- d.addEventListener('change', e => {
- _dialogCount--
- resolve(d.result || 0)
- d.remove()
- })
- })
-}
-
-UI.alert = function (message, options = {}) {
- return UI.showDialog({ message, ...options })
-}
-UI.confirm = function (message, options = {}) {
- return new Promise((resolve) => UI.showDialog({ message, buttons: ['{#Cancel#}', '{#Confirm#}'], ...options }).then(index => resolve(index >= 2)).catch(() => resolve(false)))
-}
-
-Component.register('Toast', container => {
- container.toast = new bootstrap.Toast(container, { autohide: container.state.delay > 0 })
- Util.copyFunction(container, container.toast, 'show', 'hide')
- container.addEventListener('show.bs.toast', () => {
- if (container.state.delay > 0) {
- let timer
- const startTimer = () => {
- container.state.left = container.state.delay / 1000
- timer = setInterval(() => {
- if (!container.isConnected || --container.state.left <= 0) clearInterval(timer)
- }, 1000)
- }
- startTimer()
- container.addEventListener('mouseenter', () => { clearInterval(timer); container.state.left = undefined })
- container.addEventListener('mouseleave', startTimer)
- }
- })
-}, Util.makeDom(/*html*/`
+globalThis.Component.register('Toast', container => {
+ container.toast = new bootstrap.Toast(container, { autohide: container.state.delay > 0 })
+ globalThis.Util.copyFunction(container, container.toast, 'show', 'hide')
+ container.addEventListener('show.bs.toast', () => {
+ if (container.state.delay > 0) {
+ let timer
+ const startTimer = () => {
+ container.state.left = container.state.delay / 1000
+ timer = setInterval(() => {
+ if (!container.isConnected || --container.state.left <= 0) clearInterval(timer)
+ }, 1000)
+ }
+ startTimer()
+ container.addEventListener('mouseenter', () => { clearInterval(timer); container.state.left = undefined })
+ container.addEventListener('mouseleave', startTimer)
+ }
+ })
+}, globalThis.Util.makeDom(/*html*/`
@@ -105,16 +39,19 @@ Component.register('Toast', container => {
-`), Util.makeDom(/*html*/``))
+`), globalThis.Util.makeDom(/*html*/``))
UI.toast = function (message, options = {}) {
- const delay = options.delay ?? 5000
- const t = document.createElement('Toast')
- t.state = { delay, left: delay ? delay / 1000 : undefined, type: options.type || 'primary', message, buttons: options.buttons || [] }
- $(`[toast-container="${options.container || 'default'}"]`).appendChild(t)
- Promise.resolve().then(() => t.show())
+ const delay = options.delay ?? 5000
+ const t = document.createElement('Toast')
+ t.state = { delay, left: delay ? delay / 1000 : undefined, type: options.type || 'primary', message, buttons: options.buttons || [] }
+ globalThis.$(`[toast-container="${options.container || 'default'}"]`).appendChild(t)
+ Promise.resolve().then(() => t.show())
}
UI.toastConfirm = function (message, options = {}) {
- return new Promise((resolve) => UI.toast(message, { buttons: ['{#Confirm#}'], ...options }).then(index => resolve(index === 1)).catch(() => resolve(false)))
+ return new Promise((resolve) => UI.toast(message, { buttons: ['{#Confirm#}'], ...options }).then(index => resolve(index === 1)).catch(() => resolve(false)))
}
+
+globalThis.UI = UI;
+export { UI };
diff --git a/test/lib/base.js b/test/lib/base.js
index 54a45d9..6e4b123 100644
--- a/test/lib/base.js
+++ b/test/lib/base.js
@@ -1,5 +1,5 @@
(function(global, factory) {
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@apigo.cc/state"), require("@apigo.cc/bootstrap")) : typeof define === "function" && define.amd ? define(["exports", "@apigo.cc/state", "@apigo.cc/bootstrap"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ApigoBase = {}, global.ApigoState));
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@apigo.cc/state")) : typeof define === "function" && define.amd ? define(["exports", "@apigo.cc/state"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ApigoBase = global.ApigoBase || {}, global.ApigoState));
})(this, function(exports2, state) {
"use strict";
const HTTP = {
@@ -51,122 +51,11 @@
return response;
}
};
- const APIComponent = state.Component.register("API", (container) => {
- container.request = state.NewState({ url: "", method: "GET", headers: {}, data: null, timeout: 1e4, responseType: "" });
- container.response = state.NewState({ loading: false, ok: null, status: null, error: null, headers: {}, responseType: "", result: null });
- container.result = state.NewState();
- container.do = (opt = {}) => {
- return new Promise((resolve, reject) => {
- const req = { ...container.request, ...opt };
- if (!req.url) throw new Error(".url is required");
- req.headers = { ...container.request.headers, ...opt.headers };
- container.response.loading = true;
- HTTP.request(req).then((resp) => {
- Object.keys(resp).forEach((k) => {
- if (k !== "result") container.response[k] = resp[k];
- });
- if (resp.result && typeof resp.result === "object" && container.result && typeof container.result === "object") {
- Object.assign(container.result, resp.result);
- } else {
- container.result = resp.result;
- }
- container.response.loading = false;
- if (resp.ok === false) throw new Error(resp.error);
- if (typeof resp.result === "object" && resp.result.error) throw new Error(resp.result.error);
- container.dispatchEvent(new CustomEvent("response", { detail: resp, bubbles: false }));
- resolve(resp);
- }).catch((err) => {
- var _a;
- if (!opt.noui && ((_a = globalThis.UI) == null ? void 0 : _a.toast)) UI.toast(err.message, { type: "danger" });
- container.dispatchEvent(new CustomEvent("error", { detail: err, bubbles: true }));
- reject(err);
- });
- });
- };
- let _autoTimer = null;
- container.request.__watch(null, () => {
- if (!container.hasAttribute("auto") || !container.request.url) return;
- if (_autoTimer) return;
- _autoTimer = Promise.resolve().then(() => {
- container.do();
- _autoTimer = null;
- });
- });
- });
- const UI$1 = {};
- state.Component.register("Modal", (container) => {
- container.modal = new bootstrap.Modal(container);
- container.addEventListener("bind", (e) => {
- e.detail ? container.modal.show() : container.modal.hide();
- });
- container.addEventListener("hide.bs.modal", () => {
- var _a;
- (_a = document.activeElement) == null ? void 0 : _a.blur();
- container.dispatchEvent(new CustomEvent("change", { bubbles: false, detail: false }));
- });
- state.Util.copyFunction(container, container.modal, "show", "hide");
- }, state.Util.makeDom(
- /*html*/
- `
-
-`
- ));
- state.Component.register("Dialog", state.Component.getSetupFunction("Modal"), state.Util.makeDom(
- /*html*/
- `
-
-`
- ));
- let _dialogCount = 0;
- UI$1.showDialog = function({ title = "", message = "", buttons = ["{#Close#}"], type = "body" }) {
- const d = document.body.appendChild(document.createElement("Dialog"));
- d.style.zIndex = 2e3 + ++_dialogCount;
- Promise.resolve().then(() => {
- Object.assign(d.state, { message, title, type, buttons });
- d.show();
- });
- return new Promise((resolve) => {
- d.addEventListener("change", (e) => {
- _dialogCount--;
- resolve(d.result || 0);
- d.remove();
- });
- });
- };
- UI$1.alert = function(message, options = {}) {
- return UI$1.showDialog({ message, ...options });
- };
- UI$1.confirm = function(message, options = {}) {
- return new Promise((resolve) => UI$1.showDialog({ message, buttons: ["{#Cancel#}", "{#Confirm#}"], ...options }).then((index2) => resolve(index2 >= 2)).catch(() => resolve(false)));
- };
- state.Component.register("Toast", (container) => {
+ globalThis.HTTP = HTTP;
+ const UI = {};
+ globalThis.Component.register("Toast", (container) => {
container.toast = new bootstrap.Toast(container, { autohide: container.state.delay > 0 });
- state.Util.copyFunction(container, container.toast, "show", "hide");
+ globalThis.Util.copyFunction(container, container.toast, "show", "hide");
container.addEventListener("show.bs.toast", () => {
if (container.state.delay > 0) {
let timer;
@@ -184,7 +73,7 @@
container.addEventListener("mouseleave", startTimer);
}
});
- }, state.Util.makeDom(
+ }, globalThis.Util.makeDom(
/*html*/
`
@@ -206,21 +95,22 @@
`
- ), state.Util.makeDom(
+ ), globalThis.Util.makeDom(
/*html*/
``
));
- UI$1.toast = function(message, options = {}) {
+ UI.toast = function(message, options = {}) {
const delay = options.delay ?? 5e3;
const t = document.createElement("Toast");
t.state = { delay, left: delay ? delay / 1e3 : void 0, type: options.type || "primary", message, buttons: options.buttons || [] };
- state.$(`[toast-container="${options.container || "default"}"]`).appendChild(t);
+ globalThis.$(`[toast-container="${options.container || "default"}"]`).appendChild(t);
Promise.resolve().then(() => t.show());
};
- UI$1.toastConfirm = function(message, options = {}) {
- return new Promise((resolve) => UI$1.toast(message, { buttons: ["{#Confirm#}"], ...options }).then((index2) => resolve(index2 === 1)).catch(() => resolve(false)));
+ UI.toastConfirm = function(message, options = {}) {
+ return new Promise((resolve) => UI.toast(message, { buttons: ["{#Confirm#}"], ...options }).then((index2) => resolve(index2 === 1)).catch(() => resolve(false)));
};
- const AUTOFORM_BLUEPRINT = state.Util.makeDom(
+ globalThis.UI = UI;
+ const AUTOFORM_BLUEPRINT = globalThis.Util.makeDom(
/*html*/
`
@@ -261,29 +151,29 @@
`
);
- const AUTOFORM_STYLE = state.Util.makeDom(
+ const AUTOFORM_STYLE = globalThis.Util.makeDom(
/*html*/
``
);
- state.Component.register("AutoForm", (container) => {
+ globalThis.Component.register("AutoForm", (container) => {
if (!container.state.schema) container.state.schema = [];
- const ensureProxy = (v) => v && typeof v === "object" && !v.__isProxy ? state.NewState(v) : v;
+ const ensureProxy = (v) => v && typeof v === "object" && !v.__isProxy ? globalThis.NewState(v) : v;
container.state.__watch("data", (v) => container.data = ensureProxy(v));
container.data = ensureProxy(container.state.data || {});
container.vertical = container.hasAttribute("vertical");
@@ -293,7 +183,7 @@
container.request = { method: "POST" };
container.response = {};
container.result = null;
- container.form = state.$(container, "form");
+ container.form = globalThis.$(container, "form");
container.submit = (opt = {}) => {
var _a, _b;
if (!container.form.reportValidity()) return (_b = (_a = globalThis.UI) == null ? void 0 : _a.toast) == null ? void 0 : _b.call(_a, "{#verify failed#}", { type: "danger" });
@@ -301,7 +191,7 @@
const req = { ...container.request, data: container.data, noui: true, ...opt };
let task = null;
if (container.api) task = container.api.do(req);
- else if (container.request.url) task = HTTP.request(req);
+ else if (container.request.url) task = globalThis.HTTP.request(req);
else return console.warn("{#please config .api or .request.url to auto submit#}");
task.then((resp) => {
container.response = resp;
@@ -310,7 +200,7 @@
container.dispatchEvent(new CustomEvent("response", { detail: resp, bubbles: false }));
}).catch((err) => {
var _a2;
- if ((_a2 = globalThis.UI) == null ? void 0 : _a2.toast) UI.toast(err.message, { type: "danger" });
+ if ((_a2 = globalThis.UI) == null ? void 0 : _a2.toast) globalThis.UI.toast(err.message, { type: "danger" });
container.dispatchEvent(new CustomEvent("error", { detail: err, bubbles: true }));
});
};
@@ -345,215 +235,17 @@
_addAutoFormComponent: (name, type) => {
const wrapper = findAnchorInBlueprint(AUTOFORM_BLUEPRINT);
if (wrapper) {
- const node = state.Util.makeDom(`<${name} $if="item.type?.toLowerCase() === '${type.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="this.data[item.name]" class="w-100">${name}>`);
+ const node = globalThis.Util.makeDom(`<${name} $if="item.type?.toLowerCase() === '${type.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="this.data[item.name]" class="w-100">${name}>`);
wrapper.appendChild(node);
}
}
};
- state.Component.register("TagsInput", (container) => {
- container._thisObj = container;
- container.addEventListener("bind", (e) => {
- container.state.tags = Array.isArray(e.detail) ? e.detail : [];
- });
- }, state.Util.makeDom(
- /*html*/
- `
-
-
-
-
-
-
-`
- ), state.Util.makeDom(
- /*html*/
- ``
- ));
- AutoForm.register("TagsInput");
- state.Component.register("DatePicker", (container) => {
- container._thisObj = container;
- container.state = state.NewState({ start: "", end: "" });
- container.addEventListener("bind", (e) => {
- var _a, _b, _c;
- container.state.start = e.detail || "";
- const form = container.closest("AutoForm");
- const name = container.getAttribute("name");
- const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
- const rangeEnd = ((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd;
- if (form && rangeEnd) {
- container.state.end = form.data[rangeEnd] || "";
- }
- });
- Object.defineProperty(container, "isRange", {
- get: () => {
- var _a, _b, _c;
- const form = container.closest("AutoForm");
- const name = container.getAttribute("name");
- const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
- return !!(((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd);
- }
- });
- Object.defineProperty(container, "value", {
- get: () => container.state.start,
- set: (v) => {
- container.state.start = v || "";
- }
- });
- container.updateStart = (val) => {
- container.state.start = val;
- container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: val }));
- };
- container.updateEnd = (val) => {
- var _a, _b, _c;
- container.state.end = val;
- const form = container.closest("AutoForm");
- const name = container.getAttribute("name");
- const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
- const rangeEnd = ((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd;
- if (form && rangeEnd) {
- form.data[rangeEnd] = val;
- }
- };
- }, state.Util.makeDom(
- /*html*/
- `
-
-
-
- -
-
-
-
-`
- ));
- state.Component.register("ColorPicker", (container) => {
- container._thisObj = container;
- container.state = state.NewState({ value: "#000000" });
- container.addEventListener("bind", (e) => {
- container.state.value = e.detail || "#000000";
- });
- Object.defineProperty(container, "value", {
- get: () => container.state.value,
- set: (v) => {
- container.state.value = v || "#000000";
- }
- });
- container.updateValue = (val) => {
- container.state.value = val;
- container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: val }));
- };
- }, state.Util.makeDom(
- /*html*/
- `
-
-
-
-
-`
- ));
- const BOOTSTRAP_ICONS = ["alarm", "archive", "arrow-left", "arrow-right", "bag", "bank", "basket", "bell", "bookmark", "box", "briefcase", "calendar", "camera", "cart", "chat", "check", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "clock", "cloud", "code", "collection", "command", "cpu", "credit-card", "cup", "dash", "database", "display", "door-closed", "download", "droplet", "earbuds", "edit", "egg", "eject", "envelope", "eraser", "eye", "file", "filter", "flag", "folder", "gear", "gem", "gift", "graph-up", "grid", "hammer", "hand-thumbs-up", "heart", "house", "image", "inbox", "info-circle", "journal", "key", "laptop", "layers", "layout-text-sidebar-reverse", "lightbulb", "link", "list", "lock", "map", "mic", "moon", "mouse", "music-note", "newspaper", "palette", "paperclip", "pause", "pencil", "person", "phone", "pie-chart", "play", "plus", "printer", "puzzle", "question-circle", "reception-4", "record", "reply", "rss", "save", "search", "send", "server", "share", "shield", "shop", "shuffle", "skip-end", "skip-start", "slash", "sliders", "smartphone", "speaker", "speedometer", "spellcheck", "square", "star", "stickies", "stop", "stopwatch", "suit-heart", "sun", "table", "tag", "tags", "telephone", "terminal", "text-paragraph", "thermometer", "three-dots", "ticket", "tools", "trash", "trophy", "truck", "tv", "umbrella", "unlock", "upload", "vector-pen", "wallet", "watch", "wifi", "window", "wrench", "x", "zoom-in", "zoom-out", "activity", "at", "award", "backspace", "badge-3d", "badge-4k", "badge-8k", "badge-ad", "badge-ar", "badge-cc", "badge-hd", "badge-tm", "badge-vo", "badge-vr", "badge-wc", "bar-chart", "battery", "bicycle", "binoculars", "blockquote-left", "blockquote-right", "book", "bookshelf", "bootstrap", "border-all", "border-bottom", "border-center", "border-inner", "border-left", "border-middle", "border-outer", "border-right", "border-style", "border-top", "border-width", "bounding-box", "box-arrow-down", "box-arrow-in-down", "box-arrow-in-left", "box-arrow-in-right", "box-arrow-in-up", "box-arrow-left", "box-arrow-right", "box-arrow-up", "box-seam", "brightness-alt-high", "brightness-alt-low", "brightness-high", "brightness-low", "broadcast", "brush", "bucket", "bug", "building", "bullseye", "calculator", "calendar-check", "calendar-date", "calendar-day", "calendar-event", "calendar-minus", "calendar-month", "calendar-plus", "calendar-range", "calendar-week", "calendar-x", "calendar2", "calendar3", "calendar4", "camera-reels", "camera-video", "capslock", "card-checklist", "card-heading", "card-image", "card-list", "card-text", "caret-down", "caret-left", "caret-right", "caret-up", "cart-check", "cart-dash", "cart-plus", "cart-x", "cash", "cash-stack", "cast", "chat-dots", "chat-left", "chat-quote", "chat-right", "chat-square", "chat-text", "check-all", "check-circle", "check-square", "circle", "clipboard", "cloud-arrow-down", "cloud-arrow-up", "cloud-check", "cloud-download", "cloud-fog", "cloud-hail", "cloud-lightning", "cloud-minus", "cloud-moon", "cloud-plus", "cloud-rain", "cloud-slash", "cloud-snow", "cloud-sun", "cloud-upload", "clouds", "cloudy", "code-slash", "code-square", "collection-play", "columns", "columns-gap", "compass", "cone", "cone-striped", "controller", "credit-card-2-back", "credit-card-2-front", "crop", "cup-straw", "cursor", "dash-circle", "dash-square", "diagram-2", "diagram-3", "diamond", "dice-1", "dice-2", "dice-3", "dice-4", "dice-5", "dice-6", "disc", "discord", "distribute-horizontal", "distribute-vertical", "door-open", "dot", "droplet-half", "easel", "egg-fried", "emoji-angry", "emoji-dizzy", "emoji-expressionless", "emoji-frown", "emoji-heart-eyes", "emoji-laughing", "emoji-neutral", "emoji-smile", "emoji-sunglasses", "emoji-wink", "envelope-open", "exclamation", "exclamation-circle", "exclamation-diamond", "exclamation-octagon", "exclamation-square", "exclamation-triangle", "eye-slash", "eyedropper", "facebook", "file-arrow-down", "file-arrow-up", "file-binary", "file-break", "file-check", "file-code", "file-diff", "file-earmark", "file-excel", "file-image", "file-lock", "file-medical", "file-minus", "file-music", "file-pdf", "file-person", "file-play", "file-plus", "file-post", "file-ppt", "file-richtext", "file-slides", "file-spreadsheet", "file-text", "file-word", "file-zip", "files", "film", "filter-circle", "filter-left", "filter-right", "filter-square", "fingerprint", "flower1", "flower2", "flower3", "folder-check", "folder-minus", "folder-plus", "folder-symlink", "folder-x", "folder2-open", "fonts", "forward", "front", "fullscreen", "fullscreen-exit", "funnel", "gear-wide", "gender-female", "gender-male", "gender-trans", "geo", "geo-alt", "github", "globe", "google", "graph-down", "grid-1x2", "grid-3x2", "grid-3x3", "grip-horizontal", "grip-vertical", "hand-index", "hand-thumbs-down", "handbag", "hash", "headphones", "headset", "heart-half", "heptagon", "hourglass", "hourglass-bottom", "hourglass-split", "hourglass-top", "house-door", "hr", "hurricane", "image-alt", "images", "infinity", "input-cursor", "instagram", "intersect", "journal-album", "journal-arrow-down", "journal-arrow-up", "journal-bookmark", "journal-check", "journal-code", "journal-medical", "journal-minus", "journal-plus", "journal-richtext", "journal-text", "journal-x", "journals", "justify", "kanban", "keyboard", "ladder", "lamp", "layers-half", "layout-sidebar", "layout-split", "layout-three-columns", "life-preserver", "lightbulb-off", "lightning", "lightning-charge", "link-45deg", "linkedin", "list-check", "list-nested", "list-ol", "list-stars", "list-task", "list-ul", "mailbox", "markdown", "mask", "mastodon", "megaphone", "menu-app", "menu-button", "messenger", "mic-mute", "minecart", "minecart-loaded", "moisture", "mouse2", "mouse3", "music-note-beamed", "music-note-list", "music-player", "node-minus", "node-plus", "nut", "octagon", "option", "outlet", "paint-bucket", "patch-check", "patch-exclamation", "patch-minus", "patch-plus", "patch-question", "pause-btn", "pause-circle", "peace", "pen", "pencil-square", "pentagon", "person-badge", "person-bounding-box", "person-circle", "person-lines-fill", "phone-landscape", "phone-vibrate", "pie-chart-fill", "pin", "pin-angle", "pin-fill", "pin-map", "pip", "play-btn", "play-circle", "plug", "plus-circle", "plus-square", "power", "question", "question-diamond", "question-square", "rainbow", "receipt", "receipt-cutoff", "reception-0", "reception-1", "reception-2", "reception-3", "record-btn", "record-circle", "record2", "recycle", "reddit", "reply-all", "router", "rulers", "safe", "save2", "sd-card", "segmented-nav", "shield-check", "shield-exclamation", "shield-lock", "shield-shaded", "shield-slash", "shift", "signpost", "signpost-2", "signpost-split", "sim", "skip-backward", "skip-forward", "slack", "slash-circle", "slash-square", "smartwatch", "snow", "snow2", "snow3", "sort-alpha-down", "sort-alpha-up", "sort-numeric-down", "sort-numeric-up", "soundwave", "speedometer2", "square-half", "stack", "star-half", "stars", "stop-btn", "stop-circle", "suit-club", "suit-diamond", "suit-spade", "sunglasses", "sunrise", "sunset", "symmetry-horizontal", "symmetry-vertical", "tablet", "tablet-landscape", "telegram", "telephone-forward", "telephone-inbound", "telephone-outbound", "telephone-plus", "telephone-x", "text-center", "text-indent-left", "text-indent-right", "text-left", "text-right", "thermometer-half", "thermometer-high", "thermometer-low", "thermometer-snow", "thermometer-sun", "three-dots-vertical", "toggle-off", "toggle-on", "toggle2-off", "toggle2-on", "tornado", "translate", "trash2", "tree", "truck-flatbed", "tsunami", "type", "type-bold", "type-h1", "type-h2", "type-h3", "type-italic", "type-strikethrough", "type-underline", "ui-checks", "ui-checks-grid", "ui-radios", "ui-radios-grid", "union", "upc", "upc-scan", "view-list", "view-stacked", "vinyl", "voicemail", "volume-down", "volume-mute", "volume-off", "volume-up", "vr", "wallet2", "water", "whatsapp", "wifi-1", "wifi-2", "wifi-off", "wind", "window-dock", "window-sidebar", "x-circle", "x-diamond", "x-octagon", "x-square", "youtube"];
- state.Component.register("IconPicker", (container) => {
- container._thisObj = container;
- container.state = state.NewState({ value: "", search: "", open: false });
- container.addEventListener("bind", (e) => {
- container.state.value = e.detail || "";
- });
- Object.defineProperty(container, "value", {
- get: () => container.state.value,
- set: (v) => {
- container.state.value = v || "";
- }
- });
- Object.defineProperty(container, "filteredIcons", {
- get: () => {
- var _a;
- const s = ((_a = container.state.search) == null ? void 0 : _a.toLowerCase()) || "";
- return BOOTSTRAP_ICONS.filter((i) => i.includes(s));
- }
- });
- container.selectIcon = (icon) => {
- container.state.value = icon;
- container.state.open = false;
- container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: icon }));
- };
- container.toggle = () => {
- container.state.open = !container.state.open;
- if (container.state.open) {
- setTimeout(() => {
- var _a;
- (_a = state.$(container, "input")) == null ? void 0 : _a.focus();
- }, 10);
- }
- };
- const onGlobalClick = (e) => {
- if (!container.contains(e.target)) {
- container.state.open = false;
- }
- };
- window.addEventListener("click", onGlobalClick);
- container.addEventListener("remove", () => window.removeEventListener("click", onGlobalClick));
- }, state.Util.makeDom(
- /*html*/
- `
-
-
-
-
-
-
-
-
-
No icons found
-
-
-
-`
- ), state.Util.makeDom(
- /*html*/
- ``
- ));
- AutoForm.register("DatePicker");
- AutoForm.register("ColorPicker");
- AutoForm.register("IconPicker");
+ globalThis.AutoForm = AutoForm;
const VirtualScroll = (options = {}) => {
const itemHeights = /* @__PURE__ */ new Map();
const groupHeights = /* @__PURE__ */ new Map();
let groupItemCount = 1;
- const avg = state.Util.newAvg();
+ const avg = globalThis.Util.newAvg();
let padTop = 0, rowGap = 0, topMargin = 0, itemMarginTop = null, itemMarginBottom = null, listInited = false;
const providedItemHeight = options.itemHeight || null;
return {
@@ -657,7 +349,355 @@
}
};
};
- state.Component.register("List", (container) => {
+ globalThis.VirtualScroll = VirtualScroll;
+ let _mouseMoverMoving = false;
+ let _mouseMoverPos = {};
+ let _mouseMoverEvents = {};
+ const MouseMover = {
+ start: (event, { onmousemove, onmouseup }) => {
+ _mouseMoverPos = { x: event.clientX, y: event.clientY, w: 0, h: 0 };
+ _mouseMoverEvents = { onmousemove, onmouseup };
+ _mouseMoverMoving = true;
+ }
+ };
+ if (typeof document !== "undefined") {
+ document.addEventListener("mouseup", (event) => {
+ var _a;
+ if (!_mouseMoverMoving) return;
+ _mouseMoverMoving = false;
+ (_a = _mouseMoverEvents.onmouseup) == null ? void 0 : _a.call(_mouseMoverEvents, { event, ..._mouseMoverPos });
+ });
+ document.addEventListener("mousemove", (event) => {
+ var _a;
+ if (!_mouseMoverMoving) return;
+ _mouseMoverPos.w = event.clientX - _mouseMoverPos.x;
+ _mouseMoverPos.h = event.clientY - _mouseMoverPos.y;
+ (_a = _mouseMoverEvents.onmousemove) == null ? void 0 : _a.call(_mouseMoverEvents, { event, ..._mouseMoverPos });
+ });
+ }
+ globalThis.MouseMover = MouseMover;
+ const APIComponent = globalThis.Component.register("API", (container) => {
+ container.request = globalThis.NewState({ url: "", method: "GET", headers: {}, data: null, timeout: 1e4, responseType: "" });
+ container.response = globalThis.NewState({ loading: false, ok: null, status: null, error: null, headers: {}, responseType: "", result: null });
+ container.result = globalThis.NewState();
+ container.do = (opt = {}) => {
+ return new Promise((resolve, reject) => {
+ const req = { ...container.request, ...opt };
+ if (!req.url) throw new Error(".url is required");
+ req.headers = { ...container.request.headers, ...opt.headers };
+ container.response.loading = true;
+ globalThis.HTTP.request(req).then((resp) => {
+ Object.keys(resp).forEach((k) => {
+ if (k !== "result") container.response[k] = resp[k];
+ });
+ if (resp.result && typeof resp.result === "object" && container.result && typeof container.result === "object") {
+ Object.assign(container.result, resp.result);
+ } else {
+ container.result = resp.result;
+ }
+ container.response.loading = false;
+ if (resp.ok === false) throw new Error(resp.error);
+ if (typeof resp.result === "object" && resp.result.error) throw new Error(resp.result.error);
+ container.dispatchEvent(new CustomEvent("response", { detail: resp, bubbles: false }));
+ resolve(resp);
+ }).catch((err) => {
+ var _a;
+ if (!opt.noui && ((_a = globalThis.UI) == null ? void 0 : _a.toast)) globalThis.UI.toast(err.message, { type: "danger" });
+ container.dispatchEvent(new CustomEvent("error", { detail: err, bubbles: true }));
+ reject(err);
+ });
+ });
+ };
+ let _autoTimer = null;
+ container.request.__watch(null, () => {
+ if (!container.hasAttribute("auto") || !container.request.url) return;
+ if (_autoTimer) return;
+ _autoTimer = Promise.resolve().then(() => {
+ container.do();
+ _autoTimer = null;
+ });
+ });
+ });
+ globalThis.Component.register("Modal", (container) => {
+ container.modal = new bootstrap.Modal(container);
+ container.addEventListener("bind", (e) => {
+ e.detail ? container.modal.show() : container.modal.hide();
+ });
+ container.addEventListener("hide.bs.modal", () => {
+ var _a;
+ (_a = document.activeElement) == null ? void 0 : _a.blur();
+ container.dispatchEvent(new CustomEvent("change", { bubbles: false, detail: false }));
+ });
+ globalThis.Util.copyFunction(container, container.modal, "show", "hide");
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+`
+ ));
+ globalThis.Component.register("Dialog", globalThis.Component.getSetupFunction("Modal"), globalThis.Util.makeDom(
+ /*html*/
+ `
+
+`
+ ));
+ let _dialogCount = 0;
+ globalThis.UI.showDialog = function({ title = "", message = "", buttons = ["{#Close#}"], type = "body" }) {
+ const d = document.body.appendChild(document.createElement("Dialog"));
+ d.style.zIndex = 2e3 + ++_dialogCount;
+ Promise.resolve().then(() => {
+ Object.assign(d.state, { message, title, type, buttons });
+ d.show();
+ });
+ return new Promise((resolve) => {
+ d.addEventListener("change", (e) => {
+ _dialogCount--;
+ resolve(d.result || 0);
+ d.remove();
+ });
+ });
+ };
+ globalThis.UI.alert = function(message, options = {}) {
+ return globalThis.UI.showDialog({ message, ...options });
+ };
+ globalThis.UI.confirm = function(message, options = {}) {
+ return new Promise((resolve) => globalThis.UI.showDialog({ message, buttons: ["{#Cancel#}", "{#Confirm#}"], ...options }).then((index2) => resolve(index2 >= 2)).catch(() => resolve(false)));
+ };
+ globalThis.Component.register("TagsInput", (container) => {
+ container._thisObj = container;
+ container.addEventListener("bind", (e) => {
+ container.state.tags = Array.isArray(e.detail) ? e.detail : [];
+ });
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+
+
+
+
+
+`
+ ), globalThis.Util.makeDom(
+ /*html*/
+ ``
+ ));
+ if (globalThis.AutoForm) {
+ globalThis.AutoForm.register("TagsInput");
+ }
+ globalThis.Component.register("DatePicker", (container) => {
+ container._thisObj = container;
+ container.state = globalThis.NewState({ start: "", end: "" });
+ container.addEventListener("bind", (e) => {
+ var _a, _b, _c;
+ container.state.start = e.detail || "";
+ const form = container.closest("AutoForm");
+ const name = container.getAttribute("name");
+ const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
+ const rangeEnd = ((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd;
+ if (form && rangeEnd) {
+ container.state.end = form.data[rangeEnd] || "";
+ }
+ });
+ Object.defineProperty(container, "isRange", {
+ get: () => {
+ var _a, _b, _c;
+ const form = container.closest("AutoForm");
+ const name = container.getAttribute("name");
+ const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
+ return !!(((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd);
+ }
+ });
+ Object.defineProperty(container, "value", {
+ get: () => container.state.start,
+ set: (v) => {
+ container.state.start = v || "";
+ }
+ });
+ container.updateStart = (val) => {
+ container.state.start = val;
+ container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: val }));
+ };
+ container.updateEnd = (val) => {
+ var _a, _b, _c;
+ container.state.end = val;
+ const form = container.closest("AutoForm");
+ const name = container.getAttribute("name");
+ const item = (_b = (_a = form == null ? void 0 : form.state) == null ? void 0 : _a.schema) == null ? void 0 : _b.find((i) => i.name === name);
+ const rangeEnd = ((_c = item == null ? void 0 : item.setting) == null ? void 0 : _c.rangeEnd) || container.rangeEnd;
+ if (form && rangeEnd) {
+ form.data[rangeEnd] = val;
+ }
+ };
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+
+
+ -
+
+
+
+`
+ ));
+ if (globalThis.AutoForm) {
+ globalThis.AutoForm.register("DatePicker");
+ }
+ globalThis.Component.register("ColorPicker", (container) => {
+ container._thisObj = container;
+ container.state = globalThis.NewState({ value: "#000000" });
+ container.addEventListener("bind", (e) => {
+ container.state.value = e.detail || "#000000";
+ });
+ Object.defineProperty(container, "value", {
+ get: () => container.state.value,
+ set: (v) => {
+ container.state.value = v || "#000000";
+ }
+ });
+ container.updateValue = (val) => {
+ container.state.value = val;
+ container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: val }));
+ };
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+
+
+
+`
+ ));
+ if (globalThis.AutoForm) {
+ globalThis.AutoForm.register("ColorPicker");
+ }
+ const BOOTSTRAP_ICONS = ["alarm", "archive", "arrow-left", "arrow-right", "bag", "bank", "basket", "bell", "bookmark", "box", "briefcase", "calendar", "camera", "cart", "chat", "check", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "clock", "cloud", "code", "collection", "command", "cpu", "credit-card", "cup", "dash", "database", "display", "door-closed", "download", "droplet", "earbuds", "edit", "egg", "eject", "envelope", "eraser", "eye", "file", "filter", "flag", "folder", "gear", "gem", "gift", "graph-up", "grid", "hammer", "hand-thumbs-up", "heart", "house", "image", "inbox", "info-circle", "journal", "key", "laptop", "layers", "layout-text-sidebar-reverse", "lightbulb", "link", "list", "lock", "map", "mic", "moon", "mouse", "music-note", "newspaper", "palette", "paperclip", "pause", "pencil", "person", "phone", "pie-chart", "play", "plus", "printer", "puzzle", "question-circle", "reception-4", "record", "reply", "rss", "save", "search", "send", "server", "share", "shield", "shop", "shuffle", "skip-end", "skip-start", "slash", "sliders", "smartphone", "speaker", "speedometer", "spellcheck", "square", "star", "stickies", "stop", "stopwatch", "suit-heart", "sun", "table", "tag", "tags", "telephone", "terminal", "text-paragraph", "thermometer", "three-dots", "ticket", "tools", "trash", "trophy", "truck", "tv", "umbrella", "unlock", "upload", "vector-pen", "wallet", "watch", "wifi", "window", "wrench", "x", "zoom-in", "zoom-out", "activity", "at", "award", "backspace", "badge-3d", "badge-4k", "badge-8k", "badge-ad", "badge-ar", "badge-cc", "badge-hd", "badge-tm", "badge-vo", "badge-vr", "badge-wc", "bar-chart", "battery", "bicycle", "binoculars", "blockquote-left", "blockquote-right", "book", "bookshelf", "bootstrap", "border-all", "border-bottom", "border-center", "border-inner", "border-left", "border-middle", "border-outer", "border-right", "border-style", "border-top", "border-width", "bounding-box", "box-arrow-down", "box-arrow-in-down", "box-arrow-in-left", "box-arrow-in-right", "box-arrow-in-up", "box-arrow-left", "box-arrow-right", "box-arrow-up", "box-seam", "brightness-alt-high", "brightness-alt-low", "brightness-high", "brightness-low", "broadcast", "brush", "bucket", "bug", "building", "bullseye", "calculator", "calendar-check", "calendar-date", "calendar-day", "calendar-event", "calendar-minus", "calendar-month", "calendar-plus", "calendar-range", "calendar-week", "calendar-x", "calendar2", "calendar3", "calendar4", "camera-reels", "camera-video", "capslock", "card-checklist", "card-heading", "card-image", "card-list", "card-text", "caret-down", "caret-left", "caret-right", "caret-up", "cart-check", "cart-dash", "cart-plus", "cart-x", "cash", "cash-stack", "cast", "chat-dots", "chat-left", "chat-quote", "chat-right", "chat-square", "chat-text", "check-all", "check-circle", "check-square", "circle", "clipboard", "cloud-arrow-down", "cloud-arrow-up", "cloud-check", "cloud-download", "cloud-fog", "cloud-hail", "cloud-lightning", "cloud-minus", "cloud-moon", "cloud-plus", "cloud-rain", "cloud-slash", "cloud-snow", "cloud-sun", "cloud-upload", "clouds", "cloudy", "code-slash", "code-square", "collection-play", "columns", "columns-gap", "compass", "cone", "cone-striped", "controller", "credit-card-2-back", "credit-card-2-front", "crop", "cup-straw", "cursor", "dash-circle", "dash-square", "diagram-2", "diagram-3", "diamond", "dice-1", "dice-2", "dice-3", "dice-4", "dice-5", "dice-6", "disc", "discord", "distribute-horizontal", "distribute-vertical", "door-open", "dot", "droplet-half", "easel", "egg-fried", "emoji-angry", "emoji-dizzy", "emoji-expressionless", "emoji-frown", "emoji-heart-eyes", "emoji-laughing", "emoji-neutral", "emoji-smile", "emoji-sunglasses", "emoji-wink", "envelope-open", "exclamation", "exclamation-circle", "exclamation-diamond", "exclamation-octagon", "exclamation-square", "exclamation-triangle", "eye-slash", "eyedropper", "facebook", "file-arrow-down", "file-arrow-up", "file-binary", "file-break", "file-check", "file-code", "file-diff", "file-earmark", "file-excel", "file-image", "file-lock", "file-medical", "file-minus", "file-music", "file-pdf", "file-person", "file-play", "file-plus", "file-post", "file-ppt", "file-richtext", "file-slides", "file-spreadsheet", "file-text", "file-word", "file-zip", "files", "film", "filter-circle", "filter-left", "filter-right", "filter-square", "fingerprint", "flower1", "flower2", "flower3", "folder-check", "folder-minus", "folder-plus", "folder-symlink", "folder-x", "folder2-open", "fonts", "forward", "front", "fullscreen", "fullscreen-exit", "funnel", "gear-wide", "gender-female", "gender-male", "gender-trans", "geo", "geo-alt", "github", "globe", "google", "graph-down", "grid-1x2", "grid-3x2", "grid-3x3", "grip-horizontal", "grip-vertical", "hand-index", "hand-thumbs-down", "handbag", "hash", "headphones", "headset", "heart-half", "heptagon", "hourglass", "hourglass-bottom", "hourglass-split", "hourglass-top", "house-door", "hr", "hurricane", "image-alt", "images", "infinity", "input-cursor", "instagram", "intersect", "journal-album", "journal-arrow-down", "journal-arrow-up", "journal-bookmark", "journal-check", "journal-code", "journal-medical", "journal-minus", "journal-plus", "journal-richtext", "journal-text", "journal-x", "journals", "justify", "kanban", "keyboard", "ladder", "lamp", "layers-half", "layout-sidebar", "layout-split", "layout-three-columns", "life-preserver", "lightbulb-off", "lightning", "lightning-charge", "link-45deg", "linkedin", "list-check", "list-nested", "list-ol", "list-stars", "list-task", "list-ul", "mailbox", "markdown", "mask", "mastodon", "megaphone", "menu-app", "menu-button", "messenger", "mic-mute", "minecart", "minecart-loaded", "moisture", "mouse2", "mouse3", "music-note-beamed", "music-note-list", "music-player", "node-minus", "node-plus", "nut", "octagon", "option", "outlet", "paint-bucket", "patch-check", "patch-exclamation", "patch-minus", "patch-plus", "patch-question", "pause-btn", "pause-circle", "peace", "pen", "pencil-square", "pentagon", "person-badge", "person-bounding-box", "person-circle", "person-lines-fill", "phone-landscape", "phone-vibrate", "pie-chart-fill", "pin", "pin-angle", "pin-fill", "pin-map", "pip", "play-btn", "play-circle", "plug", "plus-circle", "plus-square", "power", "question", "question-diamond", "question-square", "rainbow", "receipt", "receipt-cutoff", "reception-0", "reception-1", "reception-2", "reception-3", "record-btn", "record-circle", "record2", "recycle", "reddit", "reply-all", "router", "rulers", "safe", "save2", "sd-card", "segmented-nav", "shield-check", "shield-exclamation", "shield-lock", "shield-shaded", "shield-slash", "shift", "signpost", "signpost-2", "signpost-split", "sim", "skip-backward", "skip-forward", "slack", "slash-circle", "slash-square", "smartwatch", "snow", "snow2", "snow3", "sort-alpha-down", "sort-alpha-up", "sort-numeric-down", "sort-numeric-up", "soundwave", "speedometer2", "square-half", "stack", "star-half", "stars", "stop-btn", "stop-circle", "suit-club", "suit-diamond", "suit-spade", "sunglasses", "sunrise", "sunset", "symmetry-horizontal", "symmetry-vertical", "tablet", "tablet-landscape", "telegram", "telephone-forward", "telephone-inbound", "telephone-outbound", "telephone-plus", "telephone-x", "text-center", "text-indent-left", "text-indent-right", "text-left", "text-right", "thermometer-half", "thermometer-high", "thermometer-low", "thermometer-snow", "thermometer-sun", "three-dots-vertical", "toggle-off", "toggle-on", "toggle2-off", "toggle2-on", "tornado", "translate", "trash2", "tree", "truck-flatbed", "tsunami", "type", "type-bold", "type-h1", "type-h2", "type-h3", "type-italic", "type-strikethrough", "type-underline", "ui-checks", "ui-checks-grid", "ui-radios", "ui-radios-grid", "union", "upc", "upc-scan", "view-list", "view-stacked", "vinyl", "voicemail", "volume-down", "volume-mute", "volume-off", "volume-up", "vr", "wallet2", "water", "whatsapp", "wifi-1", "wifi-2", "wifi-off", "wind", "window-dock", "window-sidebar", "x-circle", "x-diamond", "x-octagon", "x-square", "youtube"];
+ globalThis.Component.register("IconPicker", (container) => {
+ container._thisObj = container;
+ container.state = globalThis.NewState({ value: "", search: "", open: false });
+ container.addEventListener("bind", (e) => {
+ container.state.value = e.detail || "";
+ });
+ Object.defineProperty(container, "value", {
+ get: () => container.state.value,
+ set: (v) => {
+ container.state.value = v || "";
+ }
+ });
+ Object.defineProperty(container, "filteredIcons", {
+ get: () => {
+ var _a;
+ const s = ((_a = container.state.search) == null ? void 0 : _a.toLowerCase()) || "";
+ return BOOTSTRAP_ICONS.filter((i) => i.includes(s));
+ }
+ });
+ container.selectIcon = (icon) => {
+ container.state.value = icon;
+ container.state.open = false;
+ container.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: icon }));
+ };
+ container.toggle = () => {
+ container.state.open = !container.state.open;
+ if (container.state.open) {
+ setTimeout(() => {
+ var _a;
+ (_a = globalThis.$(container, "input")) == null ? void 0 : _a.focus();
+ }, 10);
+ }
+ };
+ const onGlobalClick = (e) => {
+ if (!container.contains(e.target)) {
+ container.state.open = false;
+ }
+ };
+ window.addEventListener("click", onGlobalClick);
+ container.addEventListener("remove", () => window.removeEventListener("click", onGlobalClick));
+ }, globalThis.Util.makeDom(
+ /*html*/
+ `
+
+
+
+
+
+
+
+
+
No icons found
+
+
+
+`
+ ), globalThis.Util.makeDom(
+ /*html*/
+ ``
+ ));
+ if (globalThis.AutoForm) {
+ globalThis.AutoForm.register("IconPicker");
+ }
+ globalThis.Component.register("List", (container) => {
container.mode = container.getAttribute("mode") || "normal";
container.fast = container.hasAttribute("fast");
container.collapsible = container.hasAttribute("collapsible");
@@ -675,10 +715,10 @@
groupicon: "folder",
itemicon: "file"
};
- container.collapsed = state.NewState({});
+ container.collapsed = globalThis.NewState({});
container.state.renderedList = [];
const updateFlatList = () => {
- state.Util.updateDefaults(container, defaultSets);
+ globalThis.Util.updateDefaults(container, defaultSets);
const list = container.state.list || [], flatList = [];
if (container.mode === "group") {
const itemMap = {};
@@ -709,7 +749,7 @@
container.state.flatList = flatList;
};
container.state.__watch("list", updateFlatList);
- const vs = container.fast ? VirtualScroll() : null;
+ const vs = container.fast ? globalThis.VirtualScroll() : null;
let refreshing = false;
container.refresh = () => {
if (!container.fast || refreshing) return;
@@ -757,125 +797,100 @@
}
};
updateFlatList();
- }, state.Util.makeDom(
+ }, globalThis.Util.makeDom(
/*html*/
`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`
));
- state.Component.register("Nav", (container) => {
+ globalThis.Component.register("Nav", (container) => {
container.vertical = container.hasAttribute("vertical");
container.click = (item, noselect) => {
- if (!item.noselect && !noselect) state.Hash.nav = item.name;
+ if (!item.noselect && !noselect) globalThis.Hash.nav = item.name;
container.dispatchEvent(new CustomEvent("nav", { detail: { item }, bubbles: false }));
};
- }, state.Util.makeDom(
+ }, globalThis.Util.makeDom(
/*html*/
`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`
));
- let _mouseMoverMoving = false;
- let _mouseMoverPos = {};
- let _mouseMoverEvents = {};
- const MouseMover = {
- start: (event, { onmousemove, onmouseup }) => {
- _mouseMoverPos = { x: event.clientX, y: event.clientY, w: 0, h: 0 };
- _mouseMoverEvents = { onmousemove, onmouseup };
- _mouseMoverMoving = true;
- }
- };
- if (typeof document !== "undefined") {
- document.addEventListener("mouseup", (event) => {
- var _a;
- if (!_mouseMoverMoving) return;
- _mouseMoverMoving = false;
- (_a = _mouseMoverEvents.onmouseup) == null ? void 0 : _a.call(_mouseMoverEvents, { event, ..._mouseMoverPos });
- });
- document.addEventListener("mousemove", (event) => {
- var _a;
- if (!_mouseMoverMoving) return;
- _mouseMoverPos.w = event.clientX - _mouseMoverPos.x;
- _mouseMoverPos.h = event.clientY - _mouseMoverPos.y;
- (_a = _mouseMoverEvents.onmousemove) == null ? void 0 : _a.call(_mouseMoverEvents, { event, ..._mouseMoverPos });
- });
- }
- state.Component.register("Resizer", (container) => {
+ globalThis.Component.register("Resizer", (container) => {
container.isVertical = container.hasAttribute("vertical");
const min = parseInt(container.getAttribute("min")) || 10;
const max = parseInt(container.getAttribute("max")) || 1e3;
@@ -891,7 +906,7 @@
};
container.addEventListener("mousedown", (event) => {
const startSize = container.isVertical ? target.offsetHeight : target.offsetWidth;
- MouseMover.start(event, {
+ globalThis.MouseMover.start(event, {
onmousemove: ({ w, h }) => {
const newSize = getSize(startSize, w, h);
target.style[container.isVertical ? "height" : "width"] = newSize + "px";
@@ -904,38 +919,12 @@
}
});
});
- }, state.Util.makeDom(
+ }, globalThis.Util.makeDom(
/*html*/
`
`
));
- if (typeof window !== "undefined") {
- window.addEventListener("beforeunload", (event) => {
- if (state.State.exitBlocks > 0) event.preventDefault();
- });
- }
- const htmlNode = document.documentElement;
- if (!htmlNode.hasAttribute("$data-bs-theme") && !htmlNode.hasAttribute("data-bs-theme")) {
- htmlNode.setAttribute("$data-bs-theme", "LocalStorage.darkMode?'dark':'light'");
- }
- globalThis.HTTP = HTTP;
- globalThis.UI = UI$1;
- globalThis.AutoForm = AutoForm;
- globalThis.MouseMover = MouseMover;
- globalThis.VirtualScroll = VirtualScroll;
- const ApigoBase = {
- HTTP,
- UI: UI$1,
- AutoForm,
- MouseMover,
- VirtualScroll,
- State: state.State,
- List: VirtualScroll
- };
- if (typeof document !== "undefined") {
- globalThis.ApigoBase = ApigoBase;
- }
Object.defineProperty(exports2, "State", {
enumerable: true,
get: () => state.State
@@ -944,7 +933,7 @@
exports2.AutoForm = AutoForm;
exports2.HTTP = HTTP;
exports2.MouseMover = MouseMover;
- exports2.UI = UI$1;
+ exports2.UI = UI;
exports2.VirtualScroll = VirtualScroll;
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
});
diff --git a/test/lib/state.js b/test/lib/state.js
index d217def..19de524 100644
--- a/test/lib/state.js
+++ b/test/lib/state.js
@@ -1,8 +1,72 @@
(function(global, factory) {
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ApigoState = {}));
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ApigoState = global.ApigoState || {}));
})(this, function(exports2) {
"use strict";
- var _a;
+ var _a, _b;
+ const Util = {
+ clone: globalThis.structuredClone || ((obj) => JSON.parse(JSON.stringify(obj))),
+ base64: (str) => btoa(String.fromCharCode(...new TextEncoder().encode(str))),
+ unbase64: (str) => new TextDecoder().decode(Uint8Array.from(atob(str), (c) => c.charCodeAt(0))),
+ urlbase64: (str) => Util.base64(str).replace(/[+/=]/g, (m) => ({ "+": "-", "/": "", "=": "" })[m]),
+ unurlbase64: (str) => Util.unbase64(str.replace(/[-_.]/g, (m) => ({ "-": "+", "_": "/", ".": "=" })[m]).padEnd(Math.ceil(str.length / 4) * 4, "=")),
+ safeJson: (str) => {
+ try {
+ return JSON.parse(str);
+ } catch {
+ return null;
+ }
+ },
+ updateDefaults: (obj, defaults) => {
+ for (const k in defaults) if (obj[k] === void 0) obj[k] = defaults[k];
+ },
+ copyFunction: (toObj, fromObj, ...funcNames) => {
+ funcNames.forEach((name) => toObj[name] = fromObj[name].bind(fromObj));
+ },
+ getFunctionBody: (fn) => {
+ const code = fn.toString();
+ return code.slice(code.indexOf("{") + 1, code.lastIndexOf("}")).trim();
+ },
+ makeDom: (html) => {
+ if (html.includes(">\n")) html = html.replace(/>\s+<").trim();
+ const node = document.createElement("div");
+ node.innerHTML = html;
+ return node.children[0];
+ },
+ newAvg: () => {
+ let total = 0, count = 0, avg = 0;
+ return {
+ add: (v) => {
+ total += v;
+ count++;
+ return avg = total / count;
+ },
+ get: () => avg,
+ clear: () => {
+ total = 0, count = 0, avg = 0;
+ }
+ };
+ },
+ newTimeCount: () => {
+ let startTime = 0, total = 0, count = 0;
+ return {
+ start: () => startTime = (/* @__PURE__ */ new Date()).getTime(),
+ end: () => {
+ const endTime = (/* @__PURE__ */ new Date()).getTime();
+ const left = endTime - startTime;
+ startTime = endTime;
+ total += left;
+ count++;
+ return left;
+ },
+ avg: () => total / count
+ };
+ }
+ };
+ const $ = (a, b) => b ? a.querySelector(b) : document.querySelector(a);
+ const $$ = (a, b) => b ? a.querySelectorAll(b) : document.querySelectorAll(a);
+ globalThis.Util = Util;
+ globalThis.$ = $;
+ globalThis.$$ = $$;
let __activeBinding = null;
let __noWriteBack = null;
const _setActiveBinding = (val) => __activeBinding = val;
@@ -70,14 +134,67 @@
}
});
}
- const $ = (a, b) => b ? a.querySelector(b) : document.querySelector(a);
- const $$ = (a, b) => b ? a.querySelectorAll(b) : document.querySelectorAll(a);
+ globalThis.NewState = NewState;
+ let _hashParams = new URLSearchParams(typeof globalThis !== "undefined" ? ((_b = (_a = globalThis.location) == null ? void 0 : _a.hash) == null ? void 0 : _b.substring(1)) || "" : "");
+ const Hash = NewState({}, (k) => Util.safeJson(_hashParams.get(k)), (k, v) => {
+ const oldStr = _hashParams.get(k);
+ const newStr = v === void 0 ? void 0 : JSON.stringify(v);
+ if (oldStr === newStr || oldStr === null && newStr === void 0) return;
+ v === void 0 ? _hashParams.delete(k) : _hashParams.set(k, newStr);
+ globalThis.location.hash = "#" + _hashParams.toString();
+ });
+ if (typeof globalThis !== "undefined") {
+ globalThis.addEventListener("hashchange", () => {
+ var _a2;
+ const newParams = new URLSearchParams(((_a2 = globalThis.location.hash) == null ? void 0 : _a2.substring(1)) || "");
+ const keys = /* @__PURE__ */ new Set([..._hashParams.keys(), ...newParams.keys()]);
+ _hashParams = newParams;
+ keys.forEach((k) => Hash[k] = Hash[k]);
+ });
+ }
+ const LocalStorage = NewState({}, (k) => Util.safeJson(localStorage.getItem(k)), (k, v) => {
+ const oldStr = localStorage.getItem(k);
+ const newStr = v === void 0 ? void 0 : JSON.stringify(v);
+ if (oldStr === newStr || oldStr === null && newStr === void 0) return;
+ v === void 0 ? localStorage.removeItem(k) : localStorage.setItem(k, newStr);
+ });
+ const State = NewState({
+ exitBlocks: 0
+ });
+ globalThis.Hash = Hash;
+ globalThis.LocalStorage = LocalStorage;
+ globalThis.State = State;
+ let _disableRunCodeError = false;
+ const setDisableRunCodeError = (value) => {
+ _disableRunCodeError = value;
+ };
+ const _fnCache = /* @__PURE__ */ new Map();
+ function _runCode(code, vars, thisObj, extendVars) {
+ const allVars = { ...extendVars || {}, ...vars || {} };
+ const argKeys = Object.keys(allVars);
+ const argValues = Object.values(allVars);
+ const cacheKey = code + argKeys.join(",");
+ try {
+ let fn = _fnCache.get(cacheKey);
+ if (!fn) {
+ fn = new Function("Hash", "LocalStorage", "State", ...argKeys, code);
+ _fnCache.set(cacheKey, fn);
+ }
+ return fn.apply(thisObj, [globalThis.Hash, globalThis.LocalStorage, globalThis.State, ...argValues]);
+ } catch (e) {
+ if (!_disableRunCodeError) console.error(e, extendVars, [code, extendVars, vars, thisObj]);
+ return null;
+ }
+ }
+ function _returnCode(code, vars, thisObj, extendVars) {
+ if (code.includes("${")) return _runCode("return `" + code + "`", vars, thisObj, extendVars);
+ else return _runCode("return " + code, vars, thisObj, extendVars);
+ }
const _components = /* @__PURE__ */ new Map();
const _pendingTemplates = [];
const Component = {
getTemplate: (name) => document.querySelector(`template[component="${name.toUpperCase()}"]`),
register: (name, setupFunc, templateNode = null, ...globalNodes) => {
- console.log("Component.register:", name.toUpperCase());
_components.set(name.toUpperCase(), setupFunc);
if (document.readyState !== "loading") Component._addTemplate(name, templateNode, globalNodes);
else _pendingTemplates.push([name, templateNode, globalNodes]);
@@ -154,32 +271,6 @@
}
if (componentFunc) componentFunc(node);
}
- let _disableRunCodeError = false;
- function setDisableRunCodeError(value) {
- _disableRunCodeError = value;
- }
- const _fnCache = /* @__PURE__ */ new Map();
- function _runCode(code, vars, thisObj, extendVars) {
- const allVars = { ...extendVars || {}, ...vars || {} };
- const argKeys = Object.keys(allVars);
- const argValues = Object.values(allVars);
- const cacheKey = code + argKeys.join(",");
- try {
- let fn = _fnCache.get(cacheKey);
- if (!fn) {
- fn = new Function("Hash", "LocalStorage", "State", ...argKeys, code);
- _fnCache.set(cacheKey, fn);
- }
- return fn.apply(thisObj, [globalThis.Hash, globalThis.LocalStorage, globalThis.State, ...argValues]);
- } catch (e) {
- if (!_disableRunCodeError) console.error(e, extendVars, [code, extendVars, vars, thisObj]);
- return null;
- }
- }
- function _returnCode(code, vars, thisObj, extendVars) {
- if (code.includes("${")) return _runCode("return `" + code + "`", vars, thisObj, extendVars);
- else return _runCode("return " + code, vars, thisObj, extendVars);
- }
let _translator = (text, args) => {
if (!text || typeof text !== "string") return text;
return text.replace(/\{(.+?)\}/g, (match, key) => args.hasOwnProperty(key) ? args[key] : match);
@@ -354,12 +445,12 @@
}
}
}
- const _initBinding = (binding) => {
+ function _initBinding(binding) {
if (!binding.node._bindings) binding.node._bindings = [];
binding.node._bindings.push({ attr: binding.attr, prop: binding.prop, tpl: binding.tpl, exp: binding.exp });
_updateBinding(binding);
- };
- const _parseNode = (node, scanObj) => {
+ }
+ function _parseNode(node, scanObj) {
if (node._bindings) {
node._states = /* @__PURE__ */ new Set();
node._bindings.forEach((b) => _updateBinding({ node, ...b }));
@@ -372,7 +463,7 @@
if (attr.name.startsWith("$.")) {
const realAttrName = attr.name.slice(2);
let tpl = _translate(attr.value);
- if (tpl.includes("this.")) tpl = tpl.replace(/\bthis\./g, "this.parent.");
+ if (scanObj.thisObj && tpl.includes("this.")) tpl = tpl.replace(/\bthis\./g, "this.parent.");
const result = _returnCode(tpl, { thisNode: node }, { parent: scanObj.thisObj || node }, node._ref || {});
let o = node;
const prop = realAttrName.split(".");
@@ -398,7 +489,7 @@
} else {
attrs = Array.from(node.attributes).filter((a) => (a.name.startsWith("$") || a.name.startsWith("st-")) && !["$if", "$each", "st-if", "st-each"].includes(a.name) || a.name.includes("."));
}
- if (node._thisObj && scanObj.thisObj) node._thisObj.parent = scanObj.thisObj;
+ if (node._thisObj && scanObj.thisObj && node._thisObj !== scanObj.thisObj) node._thisObj.parent = scanObj.thisObj;
if (!node._thisObj) node._thisObj = scanObj.thisObj || null;
if (!node._ref) node._ref = scanObj.extendVars || {};
node._states = /* @__PURE__ */ new Set();
@@ -440,7 +531,7 @@
if (node._hasOnLoad || node._componentInitialized) Promise.resolve().then(() => node.dispatchEvent(new Event("load", { bubbles: false })));
if (node._hasOnUpdate) node.dispatchEvent(new Event("update", { bubbles: false }));
if (node._thisObj) scanObj.thisObj = node._thisObj;
- };
+ }
const _scanTree = (node, scanObj = {}) => {
if (node.nodeType === 3) {
if (node._stTranslated) return;
@@ -469,6 +560,7 @@
node.parentNode.insertBefore(template, node);
template.content.appendChild(node);
template._ref = node._ref;
+ _scanTree(template, scanObj);
return;
}
if (node.tagName === "TEMPLATE" && (node.hasAttribute("$if") || node.hasAttribute("st-if")) && (node.hasAttribute("$each") || node.hasAttribute("st-each"))) {
@@ -528,116 +620,14 @@
});
node.childNodes && node.childNodes.forEach((child) => _unbindTree(child));
};
- const _unsafeRefreshState = _scanTree;
- const Util = {
- clone: window.structuredClone || ((obj) => JSON.parse(JSON.stringify(obj))),
- base64: (str) => btoa(String.fromCharCode(...new TextEncoder().encode(str))),
- unbase64: (str) => new TextDecoder().decode(Uint8Array.from(atob(str), (c) => c.charCodeAt(0))),
- urlbase64: (str) => Util.base64(str).replace(/[+/=]/g, (m) => ({ "+": "-", "/": "", "=": "" })[m]),
- unurlbase64: (str) => Util.unbase64(str.replace(/[-_.]/g, (m) => ({ "-": "+", "_": "/", ".": "=" })[m]).padEnd(Math.ceil(str.length / 4) * 4, "=")),
- safeJson: (str) => {
- try {
- return JSON.parse(str);
- } catch {
- return null;
- }
- },
- updateDefaults: (obj, defaults) => {
- for (const k in defaults) if (obj[k] === void 0) obj[k] = defaults[k];
- },
- copyFunction: (toObj, fromObj, ...funcNames) => {
- funcNames.forEach((name) => toObj[name] = fromObj[name].bind(fromObj));
- },
- getFunctionBody: (fn) => {
- const code = fn.toString();
- return code.slice(code.indexOf("{") + 1, code.lastIndexOf("}")).trim();
- },
- makeDom: (html) => {
- if (html.includes(">\n")) html = html.replace(/>\s+<").trim();
- const node = document.createElement("div");
- node.innerHTML = html;
- return node.children[0];
- },
- newAvg: () => {
- let total = 0, count = 0, avg = 0;
- return {
- add: (v) => {
- total += v;
- count++;
- return avg = total / count;
- },
- get: () => avg,
- clear: () => {
- total = 0, count = 0, avg = 0;
- }
- };
- },
- newTimeCount: () => {
- let startTime = 0, total = 0, count = 0;
- return {
- start: () => startTime = (/* @__PURE__ */ new Date()).getTime(),
- end: () => {
- const endTime = (/* @__PURE__ */ new Date()).getTime();
- const left = endTime - startTime;
- startTime = endTime;
- total += left;
- count++;
- return left;
- },
- avg: () => total / count
- };
- }
- };
- globalThis.Util = Util;
- let _hashParams = new URLSearchParams(((_a = window.location.hash) == null ? void 0 : _a.substring(1)) || "");
- const Hash = NewState({}, (k) => Util.safeJson(_hashParams.get(k)), (k, v) => {
- const oldStr = _hashParams.get(k);
- const newStr = v === void 0 ? void 0 : JSON.stringify(v);
- if (oldStr === newStr || oldStr === null && newStr === void 0) return;
- v === void 0 ? _hashParams.delete(k) : _hashParams.set(k, newStr);
- window.location.hash = "#" + _hashParams.toString();
- });
- if (typeof window !== "undefined") {
- window.addEventListener("hashchange", () => {
- var _a2;
- const newParams = new URLSearchParams(((_a2 = window.location.hash) == null ? void 0 : _a2.substring(1)) || "");
- const keys = /* @__PURE__ */ new Set([..._hashParams.keys(), ...newParams.keys()]);
- _hashParams = newParams;
- keys.forEach((k) => Hash[k] = Hash[k]);
- });
- }
- const LocalStorage = NewState({}, (k) => Util.safeJson(localStorage.getItem(k)), (k, v) => {
- const oldStr = localStorage.getItem(k);
- const newStr = v === void 0 ? void 0 : JSON.stringify(v);
- if (oldStr === newStr || oldStr === null && newStr === void 0) return;
- v === void 0 ? localStorage.removeItem(k) : localStorage.setItem(k, newStr);
- });
- const State = NewState({
- exitBlocks: 0
- });
- globalThis.Hash = Hash;
- globalThis.LocalStorage = LocalStorage;
- globalThis.State = State;
- const ApigoState = {
- NewState,
- Component,
- $,
- $$,
- RefreshState: _unsafeRefreshState,
- SetTranslator,
- _scanTree,
- _unbindTree,
- Util,
- Hash,
- LocalStorage,
- State
- };
- if (typeof window !== "undefined") {
- window.ApigoState = ApigoState;
- }
+ globalThis.Component = Component;
+ globalThis.SetTranslator = SetTranslator;
+ globalThis.__unsafeRefreshState = _scanTree;
if (typeof document !== "undefined") {
const init = () => {
- Component._initPending();
+ if (globalThis.Component && globalThis.Component._initPending) {
+ globalThis.Component._initPending();
+ }
const htmlNode = document.documentElement;
if (!htmlNode.hasAttribute("$data-bs-theme") && !htmlNode.hasAttribute("data-bs-theme")) {
htmlNode.setAttribute("$data-bs-theme", "LocalStorage.darkMode?'dark':'light'");
@@ -655,17 +645,16 @@
if (document.readyState !== "loading") init();
else document.addEventListener("DOMContentLoaded", init, true);
}
+ const __unsafeRefreshState = _scanTree;
exports2.$ = $;
exports2.$$ = $$;
exports2.Component = Component;
exports2.Hash = Hash;
exports2.LocalStorage = LocalStorage;
exports2.NewState = NewState;
- exports2.RefreshState = _unsafeRefreshState;
exports2.SetTranslator = SetTranslator;
exports2.State = State;
exports2.Util = Util;
- exports2._scanTree = _scanTree;
- exports2._unbindTree = _unbindTree;
+ exports2.__unsafeRefreshState = __unsafeRefreshState;
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
});
diff --git a/vite.config.js b/vite.config.js
index 472a664..c27d3a7 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -28,6 +28,7 @@ export default defineConfig({
format: 'umd',
name: 'ApigoBase',
entryFileNames: 'base.js',
+ extend: true,
globals: {
'@apigo.cc/state': 'ApigoState',
'@apigo.cc/bootstrap': 'bootstrap'
@@ -37,6 +38,7 @@ export default defineConfig({
format: 'umd',
name: 'ApigoBase',
entryFileNames: 'base.min.js',
+ extend: true,
globals: {
'@apigo.cc/state': 'ApigoState',
'@apigo.cc/bootstrap': 'bootstrap'