@epxing/dashboard 0.0.0-stage → 5.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +79 -0
- package/README.md +40 -2
- package/dist/_virtual/_plugin-vue_export-helper.js +10 -0
- package/dist/_virtual/preload-helper.js +88 -0
- package/dist/assets/technology_bg-oWIS2awO.jpg +0 -0
- package/dist/src/Dashboard.js +332 -0
- package/dist/src/DashboardGrid.js +182 -0
- package/dist/src/DesignGrid.js +711 -0
- package/dist/src/DesignItem.js +63 -0
- package/dist/src/Div.js +408 -0
- package/dist/src/Header.js +385 -0
- package/dist/src/Preview.js +27 -0
- package/dist/src/Tabs.js +468 -0
- package/dist/src/Title.js +101 -0
- package/dist/src/Widget.js +266 -0
- package/dist/src/chart-request-scope.js +32 -0
- package/dist/src/design-target.js +57 -0
- package/dist/src/grid/compact.js +68 -0
- package/dist/src/grid/compat/GridItem.js +35 -0
- package/dist/src/grid/compat/GridLayout.js +76 -0
- package/dist/src/grid/designState.js +21 -0
- package/dist/src/grid/engines.js +25 -0
- package/dist/src/grid/geometry.js +44 -0
- package/dist/src/grid/gridstackParams.js +69 -0
- package/dist/src/grid/mixins.js +108 -0
- package/dist/src/grid/model.js +223 -0
- package/dist/src/grid/useViewportGate.js +55 -0
- package/dist/src/index.js +26 -0
- package/dist/src/layout-util.js +108 -0
- package/dist/src/mobile-design.js +50 -0
- package/dist/src/theme-style.js +133 -0
- package/dist/style.css +1009 -0
- package/package.json +85 -3
- package/src/Dashboard.vue +459 -0
- package/src/DashboardGrid.vue +189 -0
- package/src/DesignGrid.vue +851 -0
- package/src/DesignItem.vue +124 -0
- package/src/Div.vue +419 -0
- package/src/Header.vue +501 -0
- package/src/Preview.vue +30 -0
- package/src/Tabs.vue +484 -0
- package/src/Title.vue +107 -0
- package/src/Widget.vue +354 -0
- package/src/chart-request-scope.js +22 -0
- package/src/design-target.js +55 -0
- package/src/grid/compact.js +81 -0
- package/src/grid/compat/GridItem.vue +30 -0
- package/src/grid/compat/GridLayout.vue +76 -0
- package/src/grid/designState.js +17 -0
- package/src/grid/engines.js +22 -0
- package/src/grid/geometry.js +55 -0
- package/src/grid/gridstackParams.js +72 -0
- package/src/grid/mixins.js +114 -0
- package/src/grid/model.js +259 -0
- package/src/grid/useViewportGate.js +57 -0
- package/src/index.js +28 -0
- package/src/layout-util.js +157 -0
- package/src/mobile-design.js +50 -0
- package/src/theme-style.js +185 -0
- package/types/div.d.ts +1 -0
- package/types/index.d.ts +7 -0
- package/types/tabs.d.ts +1 -0
- package/types/title.d.ts +1 -0
- package/types/widget.d.ts +1 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { isContainerType, normalizeGridParams } from "./grid/model.js";
|
|
2
|
+
import { normalizeGridItem } from "./layout-util.js";
|
|
3
|
+
import { layoutHeight, itemRect, rectStyle, resolveGrid } from "./grid/geometry.js";
|
|
4
|
+
import { compact } from "./grid/compact.js";
|
|
5
|
+
import { createViewportGate } from "./grid/useViewportGate.js";
|
|
6
|
+
import { resolveDirective, openBlock, createElementBlock, normalizeStyle, normalizeClass, Fragment, renderList, withDirectives, renderSlot, createCommentVNode } from "vue";
|
|
7
|
+
/* empty css */
|
|
8
|
+
import _export_sfc from "../_virtual/_plugin-vue_export-helper.js";
|
|
9
|
+
const _sfc_main = {
|
|
10
|
+
name: "epx-dashboard-grid",
|
|
11
|
+
props: {
|
|
12
|
+
items: { type: Array, default: () => [] },
|
|
13
|
+
grid: { type: Object, default: () => ({}) },
|
|
14
|
+
mode: { type: String, default: "view" },
|
|
15
|
+
// all:全部挂载;current:进入可视区后挂载、不再卸载;viewport:进入挂载、远离卸载
|
|
16
|
+
// 挂载后不可变;要切换请由父组件加 key 重建
|
|
17
|
+
loadWay: { type: String, default: "all" },
|
|
18
|
+
// 显式容器宽度(测试 / 无 ResizeObserver 环境用),缺省由 ResizeObserver 测量
|
|
19
|
+
// 挂载后不可变;要切换请由父组件加 key 重建
|
|
20
|
+
width: { type: Number, default: 0 },
|
|
21
|
+
// rowHeight / gap 为 'auto' 时的换算基准(document.body 高度),由父组件传入并随 resize 更新
|
|
22
|
+
bodyHeight: { type: Number, default: 0 },
|
|
23
|
+
// 可视区门控的滚动容器:从本组件向上找最近的匹配祖先,找不到用视口
|
|
24
|
+
scrollRootSelector: { type: String, default: ".epx-dashboard__container" }
|
|
25
|
+
},
|
|
26
|
+
directives: {
|
|
27
|
+
// 用指令而不是函数 ref:指令的 mounted / unmounted 都能拿到元素本身,函数 ref 卸载时只给 null。
|
|
28
|
+
// 值是 entry:容器项(entry.gated 为 false)不交给观察器(R14:容器本身不门控,门控作用在容器内的项上)
|
|
29
|
+
gate: {
|
|
30
|
+
mounted(el, binding) {
|
|
31
|
+
if (binding.value.gated) binding.instance.gateObserve(el, binding.value.item.id);
|
|
32
|
+
},
|
|
33
|
+
unmounted(el, binding) {
|
|
34
|
+
binding.instance.gateUnobserve(el);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
data() {
|
|
39
|
+
const needGate = this.loadWay === "current" || this.loadWay === "viewport";
|
|
40
|
+
const gateUnsupported = needGate && !(typeof window !== "undefined" && typeof window.IntersectionObserver === "function");
|
|
41
|
+
return { measuredWidth: 0, activeIds: {}, gateUnsupported };
|
|
42
|
+
},
|
|
43
|
+
computed: {
|
|
44
|
+
gridParams() {
|
|
45
|
+
return normalizeGridParams(this.grid);
|
|
46
|
+
},
|
|
47
|
+
containerWidth() {
|
|
48
|
+
return this.width || this.measuredWidth;
|
|
49
|
+
},
|
|
50
|
+
resolved() {
|
|
51
|
+
return resolveGrid(this.gridParams, { containerWidth: this.containerWidth, bodyHeight: this.bodyHeight });
|
|
52
|
+
},
|
|
53
|
+
// 整页悬浮(grid.mode === 'float',R30):全部项按悬浮处理——不压紧、按 z 叠放,与设计态只有悬浮层一致
|
|
54
|
+
floatMode() {
|
|
55
|
+
return this.gridParams.mode === "float";
|
|
56
|
+
},
|
|
57
|
+
// 渲染用坐标:与旧布局库 mounted 后的 compact 同一算法(空隙上移、重叠推下,static 项不动、float 项原样),
|
|
58
|
+
// 算出的是副本,不写回 props / 页面配置;每项 { item: 原始项, pos: 压紧后的坐标副本 }。整页悬浮时全部项按悬浮算
|
|
59
|
+
compacted() {
|
|
60
|
+
const live = (this.items || []).filter(Boolean);
|
|
61
|
+
const positions = compact(this.floatMode ? live.map((item) => ({ ...item, float: true })) : live);
|
|
62
|
+
return live.map((item, idx) => ({ item, pos: positions[idx] }));
|
|
63
|
+
},
|
|
64
|
+
// 只做几何计算、不改写 item:规范化交给下面 items 的 deep watch,在渲染前把
|
|
65
|
+
// x/y/w/h 落定成数字,这里保持 computed 该有的无副作用约定
|
|
66
|
+
entries() {
|
|
67
|
+
return this.compacted.map(({ item, pos }) => {
|
|
68
|
+
const rect = itemRect(pos, this.resolved);
|
|
69
|
+
const style = rectStyle(rect);
|
|
70
|
+
const float = this.floatMode || !!item.float;
|
|
71
|
+
if (float) style.zIndex = 10 + (Number(item.z) || 0);
|
|
72
|
+
return { item, rect, style, float, gated: !isContainerType(item.contentType) };
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
containerStyle() {
|
|
76
|
+
return { height: layoutHeight(this.compacted.map((e) => e.pos), this.resolved) + "px" };
|
|
77
|
+
},
|
|
78
|
+
gated() {
|
|
79
|
+
return (this.loadWay === "current" || this.loadWay === "viewport") && !this.gateUnsupported;
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
watch: {
|
|
83
|
+
// 规范化 x/y/w/h(原来放在 entries computed 里就地改写 item,违反 computed 无副作用
|
|
84
|
+
// 约定,items 若来自 readonly() 源还会静默失败);顺带把已经不在 items 里的项的
|
|
85
|
+
// 激活记录一并清掉,别让 activeIds 只增不减。deep: 1 只跟踪数组层与元素身份,不深度
|
|
86
|
+
// 追踪每项内部字段——这里就地写 item.x/y/w/h,用 deep: true 会和这次改写形成响应式回环。
|
|
87
|
+
// immediate 让规范化在首帧渲染前就完成,entries 求值时数字已经就绪。
|
|
88
|
+
items: {
|
|
89
|
+
deep: 1,
|
|
90
|
+
handler(v) {
|
|
91
|
+
const list = v || [];
|
|
92
|
+
const alive = /* @__PURE__ */ new Set();
|
|
93
|
+
for (const item of list) {
|
|
94
|
+
if (!item) continue;
|
|
95
|
+
normalizeGridItem(item);
|
|
96
|
+
alive.add(String(item.id));
|
|
97
|
+
}
|
|
98
|
+
for (const id in this.activeIds) if (!alive.has(id)) delete this.activeIds[id];
|
|
99
|
+
},
|
|
100
|
+
immediate: true
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
methods: {
|
|
104
|
+
shouldRender(item) {
|
|
105
|
+
if (!this.gated) return true;
|
|
106
|
+
if (isContainerType(item.contentType) || item.keepAlive) return true;
|
|
107
|
+
return !!this.activeIds[item.id];
|
|
108
|
+
},
|
|
109
|
+
gateObserve(el, id) {
|
|
110
|
+
if (this.gate) this.gate.observe(el, id);
|
|
111
|
+
},
|
|
112
|
+
gateUnobserve(el) {
|
|
113
|
+
if (this.gate) this.gate.unobserve(el);
|
|
114
|
+
if (el.dataset && el.dataset.itemId != null) delete this.activeIds[el.dataset.itemId];
|
|
115
|
+
},
|
|
116
|
+
measure() {
|
|
117
|
+
if (this.$refs.root) this.measuredWidth = this.$refs.root.offsetWidth;
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
mounted() {
|
|
121
|
+
if (!this.width) {
|
|
122
|
+
this.measure();
|
|
123
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
124
|
+
this.resizeObserver = new ResizeObserver(() => this.measure());
|
|
125
|
+
this.resizeObserver.observe(this.$refs.root);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (this.loadWay === "current" || this.loadWay === "viewport") {
|
|
129
|
+
const root = this.scrollRootSelector && this.$el.closest(this.scrollRootSelector) || null;
|
|
130
|
+
this.gate = createViewportGate({
|
|
131
|
+
root,
|
|
132
|
+
sticky: this.loadWay === "current",
|
|
133
|
+
onChange: (id, active) => {
|
|
134
|
+
if (active) this.activeIds[id] = true;
|
|
135
|
+
else delete this.activeIds[id];
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
if (!this.gate.supported) {
|
|
139
|
+
this.gateUnsupported = true;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
for (const el of Array.from(this.$el.children)) {
|
|
143
|
+
if (el.dataset && el.dataset.itemId != null && el.dataset.gated === "1") this.gate.observe(el, el.dataset.itemId);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
beforeUnmount() {
|
|
148
|
+
if (this.resizeObserver) this.resizeObserver.disconnect();
|
|
149
|
+
if (this.gate) this.gate.destroy();
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const _hoisted_1 = ["data-item-id", "data-gated"];
|
|
153
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
154
|
+
const _directive_gate = resolveDirective("gate");
|
|
155
|
+
return openBlock(), createElementBlock("div", {
|
|
156
|
+
ref: "root",
|
|
157
|
+
class: normalizeClass(["epx-dashboard-grid", { "epx-dashboard-grid--float-mode": $options.floatMode }]),
|
|
158
|
+
style: normalizeStyle($options.containerStyle)
|
|
159
|
+
}, [
|
|
160
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($options.entries, (entry) => {
|
|
161
|
+
return withDirectives((openBlock(), createElementBlock("div", {
|
|
162
|
+
key: entry.item.id,
|
|
163
|
+
class: normalizeClass(["epx-dashboard-grid__item", { "epx-dashboard-grid__item--float": entry.float, "epx-dashboard-grid__item--static": !!entry.item.static }]),
|
|
164
|
+
style: normalizeStyle(entry.style),
|
|
165
|
+
"data-item-id": entry.item.id,
|
|
166
|
+
"data-gated": entry.gated ? "1" : null
|
|
167
|
+
}, [
|
|
168
|
+
$options.shouldRender(entry.item) ? renderSlot(_ctx.$slots, "item", {
|
|
169
|
+
key: 0,
|
|
170
|
+
item: entry.item,
|
|
171
|
+
rect: entry.rect
|
|
172
|
+
}) : createCommentVNode("", true)
|
|
173
|
+
], 14, _hoisted_1)), [
|
|
174
|
+
[_directive_gate, entry]
|
|
175
|
+
]);
|
|
176
|
+
}), 128))
|
|
177
|
+
], 6);
|
|
178
|
+
}
|
|
179
|
+
const DashboardGrid = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
|
|
180
|
+
export {
|
|
181
|
+
DashboardGrid as default
|
|
182
|
+
};
|