@schukai/monster 4.128.0 → 4.128.2
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/package.json +1 -1
- package/source/components/datatable/datatable.mjs +239 -46
- package/source/components/datatable/style/datatable.pcss +5 -0
- package/source/components/datatable/stylesheet/datatable.mjs +1 -1
- package/source/components/style/floating-ui.pcss +8 -0
- package/source/components/stylesheet/floating-ui.mjs +1 -1
- package/source/dom/customelement.mjs +25 -25
- package/source/dom/updater.mjs +25 -21
- package/test/cases/components/datatable/drag-scroll.mjs +258 -0
|
@@ -3,6 +3,8 @@ div[data-monster-role=popper] {
|
|
|
3
3
|
box-sizing: border-box;
|
|
4
4
|
display: none;
|
|
5
5
|
padding: 1.1em;
|
|
6
|
+
max-width: var(--monster-popper-max-width, calc(100vw - 2rem));
|
|
7
|
+
max-height: var(--monster-popper-max-height, calc(100vh - 2rem));
|
|
6
8
|
z-index: var(--monster-z-index-modal);
|
|
7
9
|
background: var(--monster-bg-color-primary-1);
|
|
8
10
|
color: var(--monster-color-primary-1);
|
|
@@ -21,6 +23,12 @@ div[data-monster-role=popper] {
|
|
|
21
23
|
top: 0;
|
|
22
24
|
left: 0;
|
|
23
25
|
|
|
26
|
+
& > [part=content] {
|
|
27
|
+
overflow: auto;
|
|
28
|
+
max-width: 100%;
|
|
29
|
+
max-height: var(--monster-popper-content-max-height, calc(100vh - 4.2rem));
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
& div[data-monster-role=arrow] {
|
|
25
33
|
position: absolute;
|
|
26
34
|
width: calc(2 * max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance)));
|
|
@@ -25,7 +25,7 @@ try {
|
|
|
25
25
|
FloatingUiStyleSheet.insertRule(
|
|
26
26
|
`
|
|
27
27
|
@layer floatingui {
|
|
28
|
-
div[data-monster-role=popper]{align-content:center;background:var(--monster-bg-color-primary-1);border-color:var(--monster-bg-color-primary-4);border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);box-shadow:var(--monster-box-shadow-1);box-sizing:border-box;color:var(--monster-color-primary-1);display:none;justify-content:space-between;left:0;padding:1.1em;position:absolute;top:0;width:-moz-max-content;width:max-content;z-index:var(--monster-z-index-modal)}div[data-monster-role=popper] div[data-monster-role=arrow]{background:var(--monster-bg-color-primary-1);height:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);pointer-events:none;position:absolute;width:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);z-index:-1}
|
|
28
|
+
div[data-monster-role=popper]{align-content:center;background:var(--monster-bg-color-primary-1);border-color:var(--monster-bg-color-primary-4);border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);box-shadow:var(--monster-box-shadow-1);box-sizing:border-box;color:var(--monster-color-primary-1);display:none;justify-content:space-between;left:0;max-height:var(--monster-popper-max-height,calc(100vh - 2rem));max-width:var(--monster-popper-max-width,calc(100vw - 2rem));padding:1.1em;position:absolute;top:0;width:-moz-max-content;width:max-content;z-index:var(--monster-z-index-modal)}div[data-monster-role=popper]>[part=content]{max-height:var(--monster-popper-content-max-height,calc(100vh - 4.2rem));max-width:100%;overflow:auto}div[data-monster-role=popper] div[data-monster-role=arrow]{background:var(--monster-bg-color-primary-1);height:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);pointer-events:none;position:absolute;width:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);z-index:-1}
|
|
29
29
|
}`,
|
|
30
30
|
0,
|
|
31
31
|
);
|
|
@@ -932,33 +932,33 @@ function attachChildMutationObserver() {
|
|
|
932
932
|
return;
|
|
933
933
|
}
|
|
934
934
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
935
|
+
self[childMutationTimerSymbol] = setTimeout(() => {
|
|
936
|
+
self[childMutationTimerSymbol] = null;
|
|
937
|
+
if (!self.isConnected) {
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
940
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
941
|
+
if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
const updaters = getLinkedObjects(self, customElementUpdaterLinkSymbol);
|
|
946
|
+
for (const list of updaters) {
|
|
947
|
+
for (const updater of list) {
|
|
948
|
+
if (
|
|
949
|
+
typeof updater?.isDisposed === "function" &&
|
|
950
|
+
updater.isDisposed() === true
|
|
951
|
+
) {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (!updater?.[internalSymbol]?.element?.isConnected) {
|
|
956
|
+
continue;
|
|
957
|
+
}
|
|
944
958
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
if (
|
|
949
|
-
typeof updater?.isDisposed === "function" &&
|
|
950
|
-
updater.isDisposed() === true
|
|
951
|
-
) {
|
|
952
|
-
continue;
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
if (!updater?.[internalSymbol]?.element?.isConnected) {
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
updater.run().catch((e) => {
|
|
960
|
-
addErrorAttribute(self, e);
|
|
961
|
-
});
|
|
959
|
+
updater.run().catch((e) => {
|
|
960
|
+
addErrorAttribute(self, e);
|
|
961
|
+
});
|
|
962
962
|
}
|
|
963
963
|
}
|
|
964
964
|
}, 50);
|
package/source/dom/updater.mjs
CHANGED
|
@@ -161,15 +161,15 @@ class Updater extends Base {
|
|
|
161
161
|
return Promise.resolve();
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
const real = this[internalSymbol].subject.getRealSubject();
|
|
165
|
+
const diffResult = diff(this[internalSymbol].last, real);
|
|
166
|
+
this[internalSymbol].last = clone(real);
|
|
167
|
+
if (diffResult.length === 0) {
|
|
168
|
+
return Promise.resolve();
|
|
169
|
+
}
|
|
170
|
+
this[pendingDiffsSymbol].push(diffResult);
|
|
171
|
+
return this[processQueueSymbol]();
|
|
172
|
+
});
|
|
173
173
|
this[internalSymbol].subject.attachObserver(this[subjectObserverSymbol]);
|
|
174
174
|
}
|
|
175
175
|
|
|
@@ -464,7 +464,10 @@ function getControlEventHandler() {
|
|
|
464
464
|
* @param {Event} event
|
|
465
465
|
*/
|
|
466
466
|
this[symbol] = (event) => {
|
|
467
|
-
if (
|
|
467
|
+
if (
|
|
468
|
+
this[disposedSymbol] === true ||
|
|
469
|
+
!this[internalSymbol].element?.isConnected
|
|
470
|
+
) {
|
|
468
471
|
return;
|
|
469
472
|
}
|
|
470
473
|
|
|
@@ -857,16 +860,16 @@ function insertElement(change) {
|
|
|
857
860
|
);
|
|
858
861
|
|
|
859
862
|
for (const [, node] of Object.entries(nodes)) {
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
863
|
+
if (
|
|
864
|
+
!available.has(
|
|
865
|
+
node.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE),
|
|
866
|
+
)
|
|
867
|
+
) {
|
|
868
|
+
try {
|
|
869
|
+
teardownManagedSubtree(node);
|
|
870
|
+
containerElement.removeChild(node);
|
|
871
|
+
} catch (e) {
|
|
872
|
+
addErrorAttribute(containerElement, e);
|
|
870
873
|
}
|
|
871
874
|
}
|
|
872
875
|
}
|
|
@@ -1285,7 +1288,8 @@ function preparePatchedNode(node, value) {
|
|
|
1285
1288
|
typeof value === "number" ||
|
|
1286
1289
|
typeof value === "boolean"
|
|
1287
1290
|
) {
|
|
1288
|
-
node.textContent =
|
|
1291
|
+
node.textContent =
|
|
1292
|
+
value === null || value === undefined ? "" : String(value);
|
|
1289
1293
|
return node;
|
|
1290
1294
|
}
|
|
1291
1295
|
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import * as chai from "chai";
|
|
2
|
+
import { chaiDom } from "../../../util/chai-dom.mjs";
|
|
3
|
+
import { initJSDOM } from "../../../util/jsdom.mjs";
|
|
4
|
+
|
|
5
|
+
const expect = chai.expect;
|
|
6
|
+
chai.use(chaiDom);
|
|
7
|
+
|
|
8
|
+
function dispatchPointerEvent(target, type, options = {}) {
|
|
9
|
+
const event = new Event(type, {
|
|
10
|
+
bubbles: true,
|
|
11
|
+
cancelable: true,
|
|
12
|
+
composed: true,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const values = {
|
|
16
|
+
button: 0,
|
|
17
|
+
isPrimary: true,
|
|
18
|
+
pointerId: 1,
|
|
19
|
+
clientX: 0,
|
|
20
|
+
clientY: 0,
|
|
21
|
+
...options,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
for (const [key, value] of Object.entries(values)) {
|
|
25
|
+
Object.defineProperty(event, key, {
|
|
26
|
+
configurable: true,
|
|
27
|
+
value,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
target.dispatchEvent(event);
|
|
32
|
+
return event;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("Datatable drag scroll", function () {
|
|
36
|
+
before(async function () {
|
|
37
|
+
await initJSDOM();
|
|
38
|
+
await import("element-internals-polyfill").catch(() => {});
|
|
39
|
+
await import("../../../../source/components/datatable/datatable.mjs");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
document.getElementById("mocks").innerHTML = "";
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("drags horizontally on non-interactive cells and suppresses the follow-up click", async function () {
|
|
47
|
+
const mocks = document.getElementById("mocks");
|
|
48
|
+
const datatable = document.createElement("monster-datatable");
|
|
49
|
+
datatable.id = "drag-scroll-table";
|
|
50
|
+
datatable.innerHTML = `
|
|
51
|
+
<template id="drag-scroll-table-row">
|
|
52
|
+
<div data-monster-head="Name">Alpha</div>
|
|
53
|
+
<div data-monster-head="Value">Beta</div>
|
|
54
|
+
</template>
|
|
55
|
+
`;
|
|
56
|
+
datatable.setOption("data", [{}, {}]);
|
|
57
|
+
mocks.appendChild(datatable);
|
|
58
|
+
|
|
59
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
60
|
+
|
|
61
|
+
const scroll = datatable.shadowRoot.querySelector(
|
|
62
|
+
"[data-monster-role=table-scroll]",
|
|
63
|
+
);
|
|
64
|
+
const cell = datatable.shadowRoot.querySelector(
|
|
65
|
+
"[data-monster-role=datatable] > div",
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(scroll).to.exist;
|
|
69
|
+
expect(cell).to.exist;
|
|
70
|
+
|
|
71
|
+
Object.defineProperty(scroll, "clientWidth", {
|
|
72
|
+
configurable: true,
|
|
73
|
+
value: 200,
|
|
74
|
+
});
|
|
75
|
+
Object.defineProperty(scroll, "scrollWidth", {
|
|
76
|
+
configurable: true,
|
|
77
|
+
value: 600,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
scroll.scrollLeft = 120;
|
|
81
|
+
|
|
82
|
+
let clickCount = 0;
|
|
83
|
+
cell.addEventListener("click", () => {
|
|
84
|
+
clickCount += 1;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
dispatchPointerEvent(cell, "pointerdown", {
|
|
88
|
+
clientX: 100,
|
|
89
|
+
clientY: 20,
|
|
90
|
+
});
|
|
91
|
+
dispatchPointerEvent(window, "pointermove", {
|
|
92
|
+
clientX: 40,
|
|
93
|
+
clientY: 24,
|
|
94
|
+
});
|
|
95
|
+
dispatchPointerEvent(window, "pointerup", {
|
|
96
|
+
clientX: 40,
|
|
97
|
+
clientY: 24,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(scroll.scrollLeft).to.equal(180);
|
|
101
|
+
expect(scroll.classList.contains("is-dragging")).to.equal(false);
|
|
102
|
+
|
|
103
|
+
cell.dispatchEvent(
|
|
104
|
+
new window.MouseEvent("click", {
|
|
105
|
+
bubbles: true,
|
|
106
|
+
cancelable: true,
|
|
107
|
+
composed: true,
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
expect(clickCount).to.equal(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("does not break clicks on embedded controls", async function () {
|
|
115
|
+
const mocks = document.getElementById("mocks");
|
|
116
|
+
const datatable = document.createElement("monster-datatable");
|
|
117
|
+
datatable.id = "drag-scroll-button-table";
|
|
118
|
+
datatable.innerHTML = `
|
|
119
|
+
<template id="drag-scroll-button-table-row">
|
|
120
|
+
<div data-monster-head="Name">Alpha</div>
|
|
121
|
+
<div data-monster-head="Action"><button type="button">Open</button></div>
|
|
122
|
+
</template>
|
|
123
|
+
`;
|
|
124
|
+
datatable.setOption("data", [{}]);
|
|
125
|
+
mocks.appendChild(datatable);
|
|
126
|
+
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
128
|
+
|
|
129
|
+
const scroll = datatable.shadowRoot.querySelector(
|
|
130
|
+
"[data-monster-role=table-scroll]",
|
|
131
|
+
);
|
|
132
|
+
const button = datatable.shadowRoot.querySelector("button");
|
|
133
|
+
|
|
134
|
+
expect(scroll).to.exist;
|
|
135
|
+
expect(button).to.exist;
|
|
136
|
+
|
|
137
|
+
Object.defineProperty(scroll, "clientWidth", {
|
|
138
|
+
configurable: true,
|
|
139
|
+
value: 200,
|
|
140
|
+
});
|
|
141
|
+
Object.defineProperty(scroll, "scrollWidth", {
|
|
142
|
+
configurable: true,
|
|
143
|
+
value: 600,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
scroll.scrollLeft = 120;
|
|
147
|
+
|
|
148
|
+
let clickCount = 0;
|
|
149
|
+
button.addEventListener("click", () => {
|
|
150
|
+
clickCount += 1;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
dispatchPointerEvent(button, "pointerdown", {
|
|
154
|
+
clientX: 100,
|
|
155
|
+
clientY: 20,
|
|
156
|
+
});
|
|
157
|
+
dispatchPointerEvent(window, "pointermove", {
|
|
158
|
+
clientX: 30,
|
|
159
|
+
clientY: 22,
|
|
160
|
+
});
|
|
161
|
+
dispatchPointerEvent(window, "pointerup", {
|
|
162
|
+
clientX: 30,
|
|
163
|
+
clientY: 22,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
button.dispatchEvent(
|
|
167
|
+
new window.MouseEvent("click", {
|
|
168
|
+
bubbles: true,
|
|
169
|
+
cancelable: true,
|
|
170
|
+
composed: true,
|
|
171
|
+
}),
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
expect(scroll.scrollLeft).to.equal(120);
|
|
175
|
+
expect(clickCount).to.equal(1);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("keeps double click copy for a single cell", async function () {
|
|
179
|
+
const mocks = document.getElementById("mocks");
|
|
180
|
+
const datatable = document.createElement("monster-datatable");
|
|
181
|
+
datatable.id = "copy-cell-table";
|
|
182
|
+
datatable.innerHTML = `
|
|
183
|
+
<template id="copy-cell-table-row">
|
|
184
|
+
<div data-monster-head="Name">Alpha</div>
|
|
185
|
+
<div data-monster-head="Value">Beta</div>
|
|
186
|
+
</template>
|
|
187
|
+
`;
|
|
188
|
+
datatable.setOption("data", [{}]);
|
|
189
|
+
mocks.appendChild(datatable);
|
|
190
|
+
|
|
191
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
192
|
+
|
|
193
|
+
const copied = [];
|
|
194
|
+
Object.defineProperty(window.navigator, "clipboard", {
|
|
195
|
+
configurable: true,
|
|
196
|
+
value: {
|
|
197
|
+
writeText: async (text) => {
|
|
198
|
+
copied.push(text);
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const cell = datatable.shadowRoot.querySelector(
|
|
204
|
+
"[data-monster-role=datatable] > div",
|
|
205
|
+
);
|
|
206
|
+
cell.dispatchEvent(
|
|
207
|
+
new window.MouseEvent("dblclick", {
|
|
208
|
+
bubbles: true,
|
|
209
|
+
cancelable: true,
|
|
210
|
+
composed: true,
|
|
211
|
+
}),
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
215
|
+
expect(copied).deep.equal(["Alpha"]);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("copies the whole row on shift click", async function () {
|
|
219
|
+
const mocks = document.getElementById("mocks");
|
|
220
|
+
const datatable = document.createElement("monster-datatable");
|
|
221
|
+
datatable.id = "copy-row-table";
|
|
222
|
+
datatable.innerHTML = `
|
|
223
|
+
<template id="copy-row-table-row">
|
|
224
|
+
<div data-monster-head="Name">Alpha</div>
|
|
225
|
+
<div data-monster-head="Value">Beta</div>
|
|
226
|
+
</template>
|
|
227
|
+
`;
|
|
228
|
+
datatable.setOption("data", [{}]);
|
|
229
|
+
mocks.appendChild(datatable);
|
|
230
|
+
|
|
231
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
232
|
+
|
|
233
|
+
const copied = [];
|
|
234
|
+
Object.defineProperty(window.navigator, "clipboard", {
|
|
235
|
+
configurable: true,
|
|
236
|
+
value: {
|
|
237
|
+
writeText: async (text) => {
|
|
238
|
+
copied.push(text);
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
const cell = datatable.shadowRoot.querySelector(
|
|
244
|
+
"[data-monster-role=datatable] > div",
|
|
245
|
+
);
|
|
246
|
+
cell.dispatchEvent(
|
|
247
|
+
new window.MouseEvent("click", {
|
|
248
|
+
bubbles: true,
|
|
249
|
+
cancelable: true,
|
|
250
|
+
composed: true,
|
|
251
|
+
shiftKey: true,
|
|
252
|
+
}),
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
256
|
+
expect(copied).deep.equal(['"Alpha";"Beta"']);
|
|
257
|
+
});
|
|
258
|
+
});
|