@schukai/monster 4.150.3 → 4.150.5
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/style/datatable.pcss +2 -2
- package/source/components/datatable/stylesheet/datatable.mjs +1 -1
- package/source/components/form/sheet.mjs +13 -8
- package/source/components/form/wizard.mjs +16 -0
- package/source/components/navigation/wizard-navigation.mjs +6 -0
- package/test/cases/components/datatable/mobile-layout.mjs +18 -0
- package/test/cases/components/form/sheet.mjs +40 -0
- package/test/cases/components/form/wizard.mjs +18 -0
- package/test/cases/components/navigation/wizard-navigation.mjs +49 -0
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.150.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.150.5"}
|
|
@@ -560,9 +560,9 @@ monster-state[data-monster-role=empty-without-action]::part(action) {
|
|
|
560
560
|
& :is(monster-button-bar, .monster-button-group) {
|
|
561
561
|
--monster-button-bar-gap: 0;
|
|
562
562
|
--monster-button-bar-item-spacing: 0;
|
|
563
|
-
--monster-control-bar-button-inline-size:
|
|
563
|
+
--monster-control-bar-button-inline-size: max-content;
|
|
564
564
|
--monster-control-bar-height: max(2.75rem, 44px);
|
|
565
|
-
--monster-control-bar-item-flex:
|
|
565
|
+
--monster-control-bar-item-flex: 0 0 auto;
|
|
566
566
|
--monster-control-bar-slot-flex: 1 1 auto;
|
|
567
567
|
box-sizing: border-box;
|
|
568
568
|
display: flex;
|
|
@@ -99,7 +99,7 @@ try {
|
|
|
99
99
|
--monster-theme-control-bg-color,var(--monster-bg-color-primary-1)
|
|
100
100
|
);border:0;border-bottom:1px solid var(--monster-theme-control-border-color);border-left:1px solid var(--monster-theme-control-border-color);border-right:1px solid var(--monster-theme-control-border-color);display:grid;gap:.35rem .75rem;grid-template-columns:minmax(5.5rem,.35fr) minmax(0,1fr);justify-content:stretch;min-height:2.75rem;overflow:visible;padding:.625rem .75rem;white-space:normal;word-break:break-word}.center:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div),.end:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div),.start:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div){justify-content:stretch}[data-monster-datatable-row-start]:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div){border-radius:var(--monster-theme-control-border-radius) var(--monster-theme-control-border-radius) 0 0;border-top:1px solid var(--monster-theme-control-border-color);margin-top:.75rem}[data-monster-datatable-row-end]:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div){border-radius:0 0 var(--monster-theme-control-border-radius) var(--monster-theme-control-border-radius);margin-bottom:.75rem}[data-monster-datatable-row-start][data-monster-datatable-row-end]:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div){border-radius:var(--monster-theme-control-border-radius)}[data-monster-features~=select]:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div){align-items:center;background-color:var(
|
|
101
101
|
--monster-theme-surface-subtle,var(--monster-bg-color-primary-2)
|
|
102
|
-
);display:flex;min-height:max(2.75rem,var(--monster-control-min-block-size,44px))}:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div):has(:is(monster-button,monster-button-bar,monster-action-button,monster-select,monster-filter-select,select[multiple])){grid-template-columns:minmax(0,1fr)}:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div) :is(monster-select,monster-filter-select,select[multiple]){box-sizing:border-box;display:block;max-width:100%;min-width:0;width:100%}:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div) :is(monster-button-bar,.monster-button-group){--monster-button-bar-gap:0;--monster-button-bar-item-spacing:0;--monster-control-bar-button-inline-size:
|
|
102
|
+
);display:flex;min-height:max(2.75rem,var(--monster-control-min-block-size,44px))}:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div):has(:is(monster-button,monster-button-bar,monster-action-button,monster-select,monster-filter-select,select[multiple])){grid-template-columns:minmax(0,1fr)}:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div) :is(monster-select,monster-filter-select,select[multiple]){box-sizing:border-box;display:block;max-width:100%;min-width:0;width:100%}:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div) :is(monster-button-bar,.monster-button-group){--monster-button-bar-gap:0;--monster-button-bar-item-spacing:0;--monster-control-bar-button-inline-size:max-content;--monster-control-bar-height:max(2.75rem,44px);--monster-control-bar-item-flex:0 0 auto;--monster-control-bar-slot-flex:1 1 auto;box-sizing:border-box;display:flex;flex-wrap:wrap;gap:0;max-width:100%;min-width:0;width:100%}:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div) :is(monster-button,monster-action-button,button,[role=button]){box-sizing:border-box;flex:1 1 8rem;min-height:max(2.75rem,var(--monster-control-min-block-size,44px));min-width:0}:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div)>:is(monster-button,monster-action-button){display:block;width:100%}.selected:is(:is(.small[data-monster-role=control] [data-monster-role=datatable])>div){background-color:var(
|
|
103
103
|
--monster-theme-accent-subtle,var(--monster-bg-color-selection-2)
|
|
104
104
|
);color:var(
|
|
105
105
|
--monster-theme-accent,var(--monster-color-selection-2)
|
|
@@ -30,6 +30,7 @@ import { isArray, isObject, isString } from "../../types/is.mjs";
|
|
|
30
30
|
import { ID } from "../../types/id.mjs";
|
|
31
31
|
import { clone } from "../../util/clone.mjs";
|
|
32
32
|
|
|
33
|
+
import "./button.mjs";
|
|
33
34
|
import { SheetStyleSheet } from "./stylesheet/sheet.mjs";
|
|
34
35
|
|
|
35
36
|
export { Sheet };
|
|
@@ -391,13 +392,17 @@ function syncToolbarState() {
|
|
|
391
392
|
|
|
392
393
|
this[addRowButtonSymbol].hidden = !addRow;
|
|
393
394
|
this[addColumnButtonSymbol].hidden = !addCol;
|
|
394
|
-
this[addRowButtonSymbol].
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
395
|
+
this[addRowButtonSymbol].setOption(
|
|
396
|
+
"disabled",
|
|
397
|
+
this.getOption("disabled", false) || !addRow,
|
|
398
|
+
);
|
|
399
|
+
this[addColumnButtonSymbol].setOption(
|
|
400
|
+
"disabled",
|
|
401
|
+
this.getOption("disabled", false) || !addCol,
|
|
402
|
+
);
|
|
398
403
|
|
|
399
|
-
this[addRowButtonSymbol].
|
|
400
|
-
this[addColumnButtonSymbol].
|
|
404
|
+
this[addRowButtonSymbol].setOption("classes.button", buttonClass);
|
|
405
|
+
this[addColumnButtonSymbol].setOption("classes.button", buttonClass);
|
|
401
406
|
if (isString(labels.addRow)) {
|
|
402
407
|
this[addRowButtonSymbol].textContent = labels.addRow;
|
|
403
408
|
}
|
|
@@ -2427,8 +2432,8 @@ function getTemplate() {
|
|
|
2427
2432
|
return `
|
|
2428
2433
|
<div data-monster-role="control" part="control">
|
|
2429
2434
|
<div data-monster-role="toolbar" part="toolbar">
|
|
2430
|
-
<button
|
|
2431
|
-
<button
|
|
2435
|
+
<monster-button data-monster-role="add-row" part="add-row"></monster-button>
|
|
2436
|
+
<monster-button data-monster-role="add-column" part="add-column"></monster-button>
|
|
2432
2437
|
</div>
|
|
2433
2438
|
<div data-monster-role="grid-wrapper" part="grid-wrapper">
|
|
2434
2439
|
<div data-monster-role="grid" part="grid"></div>
|
|
@@ -45,6 +45,7 @@ const currentPanelIndexSymbol = Symbol("currentPanelIndex");
|
|
|
45
45
|
const optionObserverSymbol = Symbol("optionObserver");
|
|
46
46
|
const idsSymbol = Symbol("ids");
|
|
47
47
|
const finalRecordSymbol = Symbol("finalRecord");
|
|
48
|
+
const slottedElementsSymbol = Symbol("slottedElements");
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* A reusable wizard container that combines content panels with `monster-wizard-navigation`.
|
|
@@ -151,6 +152,7 @@ class Wizard extends CustomElement {
|
|
|
151
152
|
panel: 0,
|
|
152
153
|
group: 0,
|
|
153
154
|
};
|
|
155
|
+
this[slottedElementsSymbol] = [];
|
|
154
156
|
|
|
155
157
|
initControlReferences.call(this);
|
|
156
158
|
initEventHandler.call(this);
|
|
@@ -170,6 +172,9 @@ class Wizard extends CustomElement {
|
|
|
170
172
|
* @return {Wizard}
|
|
171
173
|
*/
|
|
172
174
|
refresh() {
|
|
175
|
+
this[slottedElementsSymbol] = Array.from(
|
|
176
|
+
getSlottedElements.call(this) || [],
|
|
177
|
+
);
|
|
173
178
|
const records = collectPanels.call(this);
|
|
174
179
|
const groups = buildGroups.call(this, records);
|
|
175
180
|
|
|
@@ -388,6 +393,10 @@ function initControlReferences() {
|
|
|
388
393
|
|
|
389
394
|
function initEventHandler() {
|
|
390
395
|
this[slotElementSymbol]?.addEventListener("slotchange", () => {
|
|
396
|
+
const elements = Array.from(getSlottedElements.call(this) || []);
|
|
397
|
+
if (haveSameElements(this[slottedElementsSymbol], elements)) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
391
400
|
this.refresh();
|
|
392
401
|
});
|
|
393
402
|
|
|
@@ -449,6 +458,13 @@ function initEventHandler() {
|
|
|
449
458
|
});
|
|
450
459
|
}
|
|
451
460
|
|
|
461
|
+
function haveSameElements(currentElements, nextElements) {
|
|
462
|
+
return (
|
|
463
|
+
currentElements.length === nextElements.length &&
|
|
464
|
+
currentElements.every((element, index) => element === nextElements[index])
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
|
|
452
468
|
function initOptionObserver() {
|
|
453
469
|
if (this[optionObserverSymbol]) {
|
|
454
470
|
return;
|
|
@@ -19,6 +19,7 @@ const currentStepIndexSymbol = Symbol("currentStepIndex");
|
|
|
19
19
|
const stepsSymbol = Symbol("steps");
|
|
20
20
|
const isTransitioningSymbol = Symbol("isTransitioning");
|
|
21
21
|
const currentSubStepIndexSymbol = Symbol("currentSubStepIndex");
|
|
22
|
+
const activationRequestSymbol = Symbol("activationRequest");
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* A WizardNavigation component to display progress and allow navigation through a series of steps,
|
|
@@ -45,6 +46,7 @@ class WizardNavigation extends CustomElement {
|
|
|
45
46
|
this[isTransitioningSymbol] = false;
|
|
46
47
|
this[currentStepIndexSymbol] = -1;
|
|
47
48
|
this[currentSubStepIndexSymbol] = -1;
|
|
49
|
+
this[activationRequestSymbol] = 0;
|
|
48
50
|
|
|
49
51
|
initControlReferences.call(this);
|
|
50
52
|
initEventHandler.call(this);
|
|
@@ -186,7 +188,11 @@ class WizardNavigation extends CustomElement {
|
|
|
186
188
|
return;
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
const request = ++this[activationRequestSymbol];
|
|
189
192
|
await this.goToStep(mainIndex, options);
|
|
193
|
+
if (request !== this[activationRequestSymbol]) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
190
196
|
|
|
191
197
|
const stepsData = this[stepsSymbol];
|
|
192
198
|
if (!stepsData || !stepsData[mainIndex]) return;
|
|
@@ -80,6 +80,24 @@ describe("Datatable mobile layout", () => {
|
|
|
80
80
|
expect(generated).not.to.include("--monster-button-bar-gap:0.5rem");
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
+
it("measures responsive row actions at their compact width", () => {
|
|
84
|
+
expect(source).to.include(
|
|
85
|
+
"--monster-control-bar-button-inline-size: max-content",
|
|
86
|
+
);
|
|
87
|
+
expect(source).to.include(
|
|
88
|
+
"--monster-control-bar-item-flex: 0 0 auto",
|
|
89
|
+
);
|
|
90
|
+
expect(source).not.to.include(
|
|
91
|
+
"--monster-control-bar-button-inline-size: 100%",
|
|
92
|
+
);
|
|
93
|
+
expect(generated).to.include(
|
|
94
|
+
"--monster-control-bar-button-inline-size:max-content",
|
|
95
|
+
);
|
|
96
|
+
expect(generated).to.include(
|
|
97
|
+
"--monster-control-bar-item-flex:0 0 auto",
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
83
101
|
it("keeps icon-only row overflow menus compact", () => {
|
|
84
102
|
expect(source).to.include("& > monster-button-bar");
|
|
85
103
|
expect(source).to.include("--monster-action-menu-min-inline-size: auto");
|
|
@@ -27,6 +27,46 @@ describe("Sheet", function () {
|
|
|
27
27
|
expect(document.createElement("monster-sheet")).to.be.instanceof(Sheet);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
+
it("should use Monster controls for visible toolbar actions", async function () {
|
|
31
|
+
const sheet = document.createElement("monster-sheet");
|
|
32
|
+
sheet.setOptions({
|
|
33
|
+
classes: { button: "monster-button-outline-secondary" },
|
|
34
|
+
features: { addRows: true, addColumns: true },
|
|
35
|
+
labels: { addRow: "Append row", addColumn: "Append column" },
|
|
36
|
+
});
|
|
37
|
+
document.getElementById("mocks").appendChild(sheet);
|
|
38
|
+
|
|
39
|
+
const addRow = sheet.shadowRoot.querySelector(
|
|
40
|
+
'[data-monster-role="add-row"]',
|
|
41
|
+
);
|
|
42
|
+
const addColumn = sheet.shadowRoot.querySelector(
|
|
43
|
+
'[data-monster-role="add-column"]',
|
|
44
|
+
);
|
|
45
|
+
const menuItems = sheet.shadowRoot.querySelectorAll(
|
|
46
|
+
'[data-monster-role="context-menu"] [role="menuitem"]',
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(addRow.tagName).to.equal("MONSTER-BUTTON");
|
|
50
|
+
expect(addColumn.tagName).to.equal("MONSTER-BUTTON");
|
|
51
|
+
expect(addRow.textContent).to.equal("Append row");
|
|
52
|
+
expect(addColumn.textContent).to.equal("Append column");
|
|
53
|
+
expect(addRow.getOption("classes.button")).to.equal(
|
|
54
|
+
"monster-button-outline-secondary",
|
|
55
|
+
);
|
|
56
|
+
expect(addRow.getOption("disabled")).to.equal(false);
|
|
57
|
+
expect(Array.from(menuItems).every((item) => item.tagName === "BUTTON")).to
|
|
58
|
+
.equal(true);
|
|
59
|
+
|
|
60
|
+
const rowCount = sheet.value.rows.length;
|
|
61
|
+
addRow.click();
|
|
62
|
+
expect(sheet.value.rows).to.have.length(rowCount + 1);
|
|
63
|
+
|
|
64
|
+
sheet.setOption("disabled", true);
|
|
65
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
66
|
+
expect(addRow.getOption("disabled")).to.equal(true);
|
|
67
|
+
expect(addColumn.getOption("disabled")).to.equal(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
30
70
|
it("should name editable cells from their row and column labels", function () {
|
|
31
71
|
const sheet = document.createElement("monster-sheet");
|
|
32
72
|
sheet.setOptions({
|
|
@@ -98,6 +98,24 @@ describe("Wizard", function () {
|
|
|
98
98
|
).to.equal(true);
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
+
it("should ignore slot changes when the assigned panels are unchanged", async () => {
|
|
102
|
+
const mocks = document.getElementById("mocks");
|
|
103
|
+
mocks.innerHTML = html;
|
|
104
|
+
|
|
105
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
106
|
+
|
|
107
|
+
const wizard = document.getElementById("wizard-under-test");
|
|
108
|
+
const slot = wizard.shadowRoot.querySelector("slot");
|
|
109
|
+
let refreshCount = 0;
|
|
110
|
+
wizard.addEventListener("monster-wizard-refresh", () => {
|
|
111
|
+
refreshCount++;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
slot.dispatchEvent(new Event("slotchange"));
|
|
115
|
+
|
|
116
|
+
expect(refreshCount).to.equal(0);
|
|
117
|
+
});
|
|
118
|
+
|
|
101
119
|
it("should use panel-specific validation callbacks before moving forward", async function () {
|
|
102
120
|
const mocks = document.getElementById("mocks");
|
|
103
121
|
mocks.innerHTML = html;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as chai from "chai";
|
|
2
|
+
import { initJSDOM } from "../../../util/jsdom.mjs";
|
|
3
|
+
|
|
4
|
+
const expect = chai.expect;
|
|
5
|
+
|
|
6
|
+
describe("WizardNavigation", () => {
|
|
7
|
+
before(async () => {
|
|
8
|
+
await initJSDOM();
|
|
9
|
+
await import(
|
|
10
|
+
"../../../../source/components/navigation/wizard-navigation.mjs"
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
document.getElementById("mocks").innerHTML = "";
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should only dispatch the latest concurrent substep activation", async () => {
|
|
19
|
+
const mocks = document.getElementById("mocks");
|
|
20
|
+
mocks.innerHTML = `
|
|
21
|
+
<monster-wizard-navigation id="wizard-navigation-under-test">
|
|
22
|
+
<ol class="wizard-steps">
|
|
23
|
+
<li class="step">
|
|
24
|
+
<span>Account</span>
|
|
25
|
+
<ul>
|
|
26
|
+
<li>Email</li>
|
|
27
|
+
<li>Password</li>
|
|
28
|
+
</ul>
|
|
29
|
+
</li>
|
|
30
|
+
</ol>
|
|
31
|
+
</monster-wizard-navigation>
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
35
|
+
|
|
36
|
+
const navigation = document.getElementById("wizard-navigation-under-test");
|
|
37
|
+
const substeps = [];
|
|
38
|
+
navigation.addEventListener("monster-wizard-substep-changed", (event) => {
|
|
39
|
+
substeps.push(event.detail.subIndex);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await Promise.all([
|
|
43
|
+
navigation.activate(0, 0, { force: true }),
|
|
44
|
+
navigation.activate(0, 1, { force: true }),
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
expect(substeps).to.deep.equal([1]);
|
|
48
|
+
});
|
|
49
|
+
});
|