@schukai/monster 3.113.0 → 3.114.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/source/components/form/digits.mjs +372 -0
- package/source/components/form/field-set.mjs +2 -1
- package/source/components/form/form.mjs +4 -2
- package/source/components/form/login.mjs +1565 -0
- package/source/components/form/password.mjs +21 -8
- package/source/components/form/style/digits.pcss +38 -0
- package/source/components/form/style/field-set.pcss +12 -1
- package/source/components/form/style/invalid.pcss +25 -0
- package/source/components/form/style/login.pcss +112 -0
- package/source/components/form/style/password.pcss +2 -0
- package/source/components/form/stylesheet/digits.mjs +38 -0
- package/source/components/form/stylesheet/field-set.mjs +1 -1
- package/source/components/form/stylesheet/invalid.mjs +38 -0
- package/source/components/form/stylesheet/login.mjs +38 -0
- package/source/components/form/stylesheet/password.mjs +1 -1
- package/source/components/form/toggle-switch.mjs +5 -2
- package/source/components/layout/slider.mjs +34 -32
- package/source/dom/customelement.mjs +8 -6
- package/source/monster.mjs +2 -0
- package/source/types/proxyobserver.mjs +2 -4
- package/source/types/version.mjs +1 -1
- package/test/cases/monster.mjs +1 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +15 -15
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,18 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
+
## [3.114.0] - 2025-03-23
|
6
|
+
|
7
|
+
### Add Features
|
8
|
+
|
9
|
+
- new login dialog
|
10
|
+
- finalize digit control [#300](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/300)
|
11
|
+
### Changes
|
12
|
+
|
13
|
+
- update project and web tests
|
14
|
+
|
15
|
+
|
16
|
+
|
5
17
|
## [3.113.0] - 2025-03-20
|
6
18
|
|
7
19
|
### Add Features
|
package/package.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.13","@popperjs/core":"^2.11.8","buffer":"^6.0.3"},"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":"3.
|
1
|
+
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.13","@popperjs/core":"^2.11.8","buffer":"^6.0.3"},"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":"3.114.0"}
|
@@ -0,0 +1,372 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
|
3
|
+
* Node module: @schukai/monster
|
4
|
+
*
|
5
|
+
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
|
6
|
+
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
|
7
|
+
*
|
8
|
+
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
|
9
|
+
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
|
10
|
+
* For more information about purchasing a commercial license, please contact schukai GmbH.
|
11
|
+
*/
|
12
|
+
|
13
|
+
import { instanceSymbol } from "../../constants.mjs";
|
14
|
+
import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
|
15
|
+
import {
|
16
|
+
assembleMethodSymbol,
|
17
|
+
registerCustomElement,
|
18
|
+
} from "../../dom/customelement.mjs";
|
19
|
+
import { DigitsStyleSheet } from "./stylesheet/digits.mjs";
|
20
|
+
import { addErrorAttribute } from "../../dom/error.mjs";
|
21
|
+
import { Observer } from "../../types/observer.mjs";
|
22
|
+
import { CustomControl } from "../../dom/customcontrol.mjs";
|
23
|
+
import { InvalidStyleSheet } from "./stylesheet/invalid.mjs";
|
24
|
+
|
25
|
+
export { Digits };
|
26
|
+
|
27
|
+
/**
|
28
|
+
* @private
|
29
|
+
* @type {symbol}
|
30
|
+
*/
|
31
|
+
const digitsElementSymbol = Symbol("digitsElement");
|
32
|
+
|
33
|
+
/**
|
34
|
+
* A Digits
|
35
|
+
*
|
36
|
+
* @fragments /fragments/components/form/digits/
|
37
|
+
*
|
38
|
+
* @example /examples/components/form/digits-simple
|
39
|
+
*
|
40
|
+
* @since 3.113.0
|
41
|
+
* @copyright schukai GmbH
|
42
|
+
* @summary A beautiful Digits that can make your life easier and also looks good.
|
43
|
+
*/
|
44
|
+
class Digits extends CustomControl {
|
45
|
+
/**
|
46
|
+
*
|
47
|
+
*/
|
48
|
+
constructor() {
|
49
|
+
super();
|
50
|
+
initOptionObserver.call(this);
|
51
|
+
}
|
52
|
+
|
53
|
+
/**
|
54
|
+
* This method is called by the `instanceof` operator.
|
55
|
+
* @returns {symbol}
|
56
|
+
*/
|
57
|
+
static get [instanceSymbol]() {
|
58
|
+
return Symbol.for("@schukai/monster/components/form/digits@@instance");
|
59
|
+
}
|
60
|
+
|
61
|
+
/**
|
62
|
+
*
|
63
|
+
* @return {Components.Form.Digits
|
64
|
+
*/
|
65
|
+
[assembleMethodSymbol]() {
|
66
|
+
super[assembleMethodSymbol]();
|
67
|
+
|
68
|
+
setTimeout(() => {
|
69
|
+
initControlReferences.call(this);
|
70
|
+
initEventHandler.call(this);
|
71
|
+
updateDigitControls.call(this);
|
72
|
+
}, 0);
|
73
|
+
|
74
|
+
return this;
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* The current value of the Switch
|
79
|
+
*
|
80
|
+
* ```
|
81
|
+
* e = document.querySelector('monster-toggle-switch');
|
82
|
+
* console.log(e.value)
|
83
|
+
* // ↦ on
|
84
|
+
* ```
|
85
|
+
*
|
86
|
+
* @return {string}
|
87
|
+
*/
|
88
|
+
get value() {
|
89
|
+
return this.getOption("value");
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Set value
|
94
|
+
*
|
95
|
+
* ```
|
96
|
+
* e = document.querySelector('monster-toggle-switch');
|
97
|
+
* e.value="on"
|
98
|
+
* ```
|
99
|
+
*
|
100
|
+
* @property {string} value
|
101
|
+
*/
|
102
|
+
set value(value) {
|
103
|
+
const chars = String(value).split("");
|
104
|
+
|
105
|
+
this.setOption("value", value);
|
106
|
+
this.setFormValue(value);
|
107
|
+
|
108
|
+
if (chars.every(checkCharacter.bind(this))) {
|
109
|
+
this.setValidity({ badInput: false }, "");
|
110
|
+
} else {
|
111
|
+
this.setValidity(
|
112
|
+
{ badInput: true },
|
113
|
+
"The value contains invalid characters",
|
114
|
+
);
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
/**
|
119
|
+
* To set the options via the HTML Tag, the attribute `data-monster-options` must be used.
|
120
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
121
|
+
*
|
122
|
+
* The individual configuration values can be found in the table.
|
123
|
+
*
|
124
|
+
* @property {Object} templates Template definitions
|
125
|
+
* @property {string} templates.main Main template
|
126
|
+
* @property {number} digits Number of digits
|
127
|
+
* @property {string} characterSet Character set for the digits, which are allowed
|
128
|
+
*/
|
129
|
+
get defaults() {
|
130
|
+
return Object.assign({}, super.defaults, {
|
131
|
+
templates: {
|
132
|
+
main: getTemplate(),
|
133
|
+
},
|
134
|
+
|
135
|
+
digits: 4,
|
136
|
+
characterSet: "0123456789",
|
137
|
+
|
138
|
+
digitsControls: [],
|
139
|
+
value: null,
|
140
|
+
});
|
141
|
+
}
|
142
|
+
|
143
|
+
/**
|
144
|
+
* @return {string}
|
145
|
+
*/
|
146
|
+
static getTag() {
|
147
|
+
return "monster-digits";
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* @return {CSSStyleSheet[]}
|
152
|
+
*/
|
153
|
+
static getCSSStyleSheet() {
|
154
|
+
return [DigitsStyleSheet, InvalidStyleSheet];
|
155
|
+
}
|
156
|
+
|
157
|
+
/**
|
158
|
+
* @return {void}
|
159
|
+
*/
|
160
|
+
focus(options) {
|
161
|
+
const element = this[digitsElementSymbol].querySelector("input");
|
162
|
+
if (element) {
|
163
|
+
element.focus(options);
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* @return {void}
|
169
|
+
*/
|
170
|
+
blur() {
|
171
|
+
const elements = this[digitsElementSymbol].querySelectorAll("input");
|
172
|
+
if (elements) {
|
173
|
+
for (const element of elements) {
|
174
|
+
element.blur();
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* @private
|
182
|
+
*/
|
183
|
+
function initOptionObserver() {
|
184
|
+
const self = this;
|
185
|
+
|
186
|
+
let lastValue = this.getOption("value");
|
187
|
+
|
188
|
+
self.attachObserver(
|
189
|
+
new Observer(function () {
|
190
|
+
if (lastValue !== self.getOption("value")) {
|
191
|
+
lastValue = self.getOption("value");
|
192
|
+
updateDigitControls.call(self);
|
193
|
+
}
|
194
|
+
}),
|
195
|
+
);
|
196
|
+
}
|
197
|
+
|
198
|
+
/**
|
199
|
+
* @private
|
200
|
+
*/
|
201
|
+
function updateDigitControls() {
|
202
|
+
const digits = this.getOption("digits") || this.setOption("digits", 4);
|
203
|
+
|
204
|
+
const controls = [];
|
205
|
+
|
206
|
+
const values = this.getOption("value") || "";
|
207
|
+
|
208
|
+
if (this[digitsElementSymbol]) {
|
209
|
+
this[digitsElementSymbol].style.gridTemplateColumns =
|
210
|
+
`repeat(${digits}, 1fr)`;
|
211
|
+
}
|
212
|
+
|
213
|
+
for (let i = 0; i < digits; i++) {
|
214
|
+
controls.push({
|
215
|
+
value: values[i] ?? " ",
|
216
|
+
});
|
217
|
+
}
|
218
|
+
|
219
|
+
this.setOption("digitsControls", controls);
|
220
|
+
}
|
221
|
+
|
222
|
+
/**
|
223
|
+
* @private
|
224
|
+
* @param value
|
225
|
+
* @returns {boolean}
|
226
|
+
*/
|
227
|
+
function checkCharacter(value) {
|
228
|
+
const characterSet = this.getOption("characterSet");
|
229
|
+
return characterSet.includes(value);
|
230
|
+
}
|
231
|
+
|
232
|
+
/**
|
233
|
+
* @private
|
234
|
+
* @returns {initEventHandler}
|
235
|
+
*/
|
236
|
+
function initEventHandler() {
|
237
|
+
const self = this;
|
238
|
+
const element = this[digitsElementSymbol];
|
239
|
+
|
240
|
+
element.addEventListener("keydown", function (event) {
|
241
|
+
if (event.target.tagName !== "INPUT") return;
|
242
|
+
const inputControl = event.target;
|
243
|
+
|
244
|
+
const pressedKey = event.key;
|
245
|
+
|
246
|
+
if ((event.ctrlKey || event.metaKey) && pressedKey === "v") {
|
247
|
+
console.log("paste");
|
248
|
+
event.preventDefault();
|
249
|
+
|
250
|
+
navigator.clipboard
|
251
|
+
.readText()
|
252
|
+
.then((clipText) => {
|
253
|
+
self.value = clipText;
|
254
|
+
})
|
255
|
+
.catch(() => {
|
256
|
+
addErrorAttribute(this, "Error while pasting");
|
257
|
+
});
|
258
|
+
|
259
|
+
return;
|
260
|
+
}
|
261
|
+
|
262
|
+
if (pressedKey === "ArrowRight") {
|
263
|
+
const nextControl = inputControl.nextElementSibling;
|
264
|
+
if (nextControl && nextControl.tagName === "INPUT") {
|
265
|
+
event.preventDefault();
|
266
|
+
nextControl.focus();
|
267
|
+
}
|
268
|
+
return;
|
269
|
+
}
|
270
|
+
|
271
|
+
if (pressedKey === "ArrowLeft") {
|
272
|
+
const previousControl = inputControl.previousElementSibling;
|
273
|
+
if (previousControl && previousControl.tagName === "INPUT") {
|
274
|
+
event.preventDefault();
|
275
|
+
previousControl.focus();
|
276
|
+
}
|
277
|
+
return;
|
278
|
+
}
|
279
|
+
|
280
|
+
if (pressedKey === "Backspace") {
|
281
|
+
if (inputControl.value !== "" && inputControl.value !== " ") {
|
282
|
+
event.preventDefault();
|
283
|
+
inputControl.value = "";
|
284
|
+
collectValues.call(self);
|
285
|
+
return;
|
286
|
+
} else {
|
287
|
+
const previousControl = inputControl.previousElementSibling;
|
288
|
+
if (previousControl && previousControl.tagName === "INPUT") {
|
289
|
+
event.preventDefault();
|
290
|
+
previousControl.focus();
|
291
|
+
}
|
292
|
+
return;
|
293
|
+
}
|
294
|
+
}
|
295
|
+
|
296
|
+
if (pressedKey.length === 1) {
|
297
|
+
if (!checkCharacter.call(self, pressedKey)) {
|
298
|
+
event.preventDefault();
|
299
|
+
inputControl.classList.add("invalid");
|
300
|
+
|
301
|
+
setTimeout(() => {
|
302
|
+
inputControl.classList.remove("invalid");
|
303
|
+
}, 500);
|
304
|
+
return;
|
305
|
+
}
|
306
|
+
|
307
|
+
if (inputControl.value.length === 1) {
|
308
|
+
event.preventDefault();
|
309
|
+
inputControl.value = pressedKey;
|
310
|
+
const nextControl = inputControl.nextElementSibling;
|
311
|
+
if (nextControl && nextControl.tagName === "INPUT") {
|
312
|
+
nextControl.focus();
|
313
|
+
}
|
314
|
+
collectValues.call(self);
|
315
|
+
return;
|
316
|
+
}
|
317
|
+
}
|
318
|
+
});
|
319
|
+
|
320
|
+
// Input event as a fallback: On successful input, the focus changes.
|
321
|
+
element.addEventListener("input", function (event) {
|
322
|
+
if (event.target.tagName !== "INPUT") return;
|
323
|
+
if (event.target.value.length === 1) {
|
324
|
+
const nextControl = event.target.nextElementSibling;
|
325
|
+
if (nextControl && nextControl.tagName === "INPUT") {
|
326
|
+
nextControl.focus();
|
327
|
+
}
|
328
|
+
collectValues.call(self);
|
329
|
+
}
|
330
|
+
});
|
331
|
+
|
332
|
+
return this;
|
333
|
+
}
|
334
|
+
|
335
|
+
function collectValues() {
|
336
|
+
const controlsValues = Array.from(
|
337
|
+
this[digitsElementSymbol].querySelectorAll("input"),
|
338
|
+
).map((input) => input.value || " ");
|
339
|
+
this.value = controlsValues.join("");
|
340
|
+
}
|
341
|
+
|
342
|
+
/**
|
343
|
+
* @private
|
344
|
+
* @return {void}
|
345
|
+
*/
|
346
|
+
function initControlReferences() {
|
347
|
+
this[digitsElementSymbol] = this.shadowRoot.querySelector(
|
348
|
+
`[${ATTRIBUTE_ROLE}="digits"]`,
|
349
|
+
);
|
350
|
+
}
|
351
|
+
|
352
|
+
/**
|
353
|
+
* @private
|
354
|
+
* @return {string}
|
355
|
+
*/
|
356
|
+
function getTemplate() {
|
357
|
+
// language=HTML
|
358
|
+
return `
|
359
|
+
<template id="digit">
|
360
|
+
<input maxlength="1"
|
361
|
+
data-monster-attributes="
|
362
|
+
value path:digit.value">
|
363
|
+
</template>
|
364
|
+
|
365
|
+
<div data-monster-role="control" part="control" data-monster-attributes="class path:classes.control">
|
366
|
+
<div part="digits" data-monster-role="digits"
|
367
|
+
data-monster-insert="digit path:digitsControls"
|
368
|
+
tabindex="-1"></div>
|
369
|
+
</div>`;
|
370
|
+
}
|
371
|
+
|
372
|
+
registerCustomElement(Digits);
|
@@ -30,6 +30,7 @@ import "../layout/collapse.mjs";
|
|
30
30
|
import "./toggle-switch.mjs";
|
31
31
|
import { getLocaleOfDocument } from "../../dom/locale.mjs";
|
32
32
|
import { addErrorAttribute } from "../../dom/error.mjs";
|
33
|
+
import { InvalidStyleSheet } from "./stylesheet/invalid.mjs";
|
33
34
|
|
34
35
|
export { FieldSet };
|
35
36
|
|
@@ -148,7 +149,7 @@ class FieldSet extends CustomControl {
|
|
148
149
|
* @return {CSSStyleSheet[]}
|
149
150
|
*/
|
150
151
|
static getCSSStyleSheet() {
|
151
|
-
return [FieldSetStyleSheet];
|
152
|
+
return [FieldSetStyleSheet, InvalidStyleSheet];
|
152
153
|
}
|
153
154
|
|
154
155
|
/**
|
@@ -25,6 +25,7 @@ import { datasourceLinkedElementSymbol } from "../datatable/util.mjs";
|
|
25
25
|
import { FormStyleSheet } from "./stylesheet/form.mjs";
|
26
26
|
import { addAttributeToken } from "../../dom/attributes.mjs";
|
27
27
|
import { getDocument } from "../../dom/util.mjs";
|
28
|
+
import { InvalidStyleSheet } from "./stylesheet/invalid.mjs";
|
28
29
|
|
29
30
|
export { Form };
|
30
31
|
|
@@ -88,7 +89,8 @@ class Form extends DataSet {
|
|
88
89
|
},
|
89
90
|
|
90
91
|
reportValidity: {
|
91
|
-
selector:
|
92
|
+
selector:
|
93
|
+
"input,select,textarea,monster-select,monster-toggle-switch,monster-password",
|
92
94
|
},
|
93
95
|
|
94
96
|
eventProcessing: true,
|
@@ -112,7 +114,7 @@ class Form extends DataSet {
|
|
112
114
|
* @return {CSSStyleSheet[]}
|
113
115
|
*/
|
114
116
|
static getCSSStyleSheet() {
|
115
|
-
return [FormStyleSheet];
|
117
|
+
return [FormStyleSheet, InvalidStyleSheet];
|
116
118
|
}
|
117
119
|
|
118
120
|
/**
|