@schukai/monster 4.100.0 → 4.101.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
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## [4.101.0] - 2026-01-17
|
|
6
|
+
|
|
7
|
+
### Add Features
|
|
8
|
+
|
|
9
|
+
- Add control overflow property to Panel component
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [4.100.1] - 2026-01-16
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- config values [#375](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/375)
|
|
18
|
+
### Changes
|
|
19
|
+
|
|
20
|
+
- doc
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
5
24
|
## [4.100.0] - 2026-01-16
|
|
6
25
|
|
|
7
26
|
### Add Features
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"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.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"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.101.0"}
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
import { instanceSymbol } from "../../constants.mjs";
|
|
16
16
|
import { ATTRIBUTE_DISABLED, ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
assembleMethodSymbol,
|
|
19
|
+
attributeObserverSymbol,
|
|
20
|
+
registerCustomElement,
|
|
21
21
|
} from "../../dom/customelement.mjs";
|
|
22
22
|
import { isArray, isString } from "../../types/is.mjs";
|
|
23
23
|
import { validateString } from "../../types/validate.mjs";
|
|
@@ -57,313 +57,326 @@ const measurementPopperSymbol = Symbol("measurementPopper");
|
|
|
57
57
|
* @fires monster-click - Fired when button is clicked
|
|
58
58
|
*/
|
|
59
59
|
class MessageStateButton extends Popper {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
60
|
+
/**
|
|
61
|
+
* This method is called by the `instanceof` operator.
|
|
62
|
+
* @return {symbol}
|
|
63
|
+
*/
|
|
64
|
+
static get [instanceSymbol]() {
|
|
65
|
+
return Symbol.for(
|
|
66
|
+
"@schukai/monster/components/form/message-state-button@@instance",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Sets the state of the button which affects its visual appearance
|
|
72
|
+
*
|
|
73
|
+
* @param {string} state - The state to set (e.g. 'success', 'error', 'loading')
|
|
74
|
+
* @param {number} timeout - Optional timeout in milliseconds after which state is removed
|
|
75
|
+
* @return {MessageStateButton} Returns the button instance for chaining
|
|
76
|
+
* @throws {TypeError} When state is not a string or timeout is not a number
|
|
77
|
+
*/
|
|
78
|
+
setState(state, timeout) {
|
|
79
|
+
return this[buttonElementSymbol].setState(state, timeout);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* @return {MessageStateButton}
|
|
85
|
+
*/
|
|
86
|
+
removeState() {
|
|
87
|
+
return this[buttonElementSymbol].removeState();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @return {MessageStateButton|undefined}
|
|
92
|
+
*/
|
|
93
|
+
getState() {
|
|
94
|
+
return this[buttonElementSymbol].getState();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* To set the options via the HTML tag, the attribute `data-monster-options` must be used.
|
|
99
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
|
100
|
+
*
|
|
101
|
+
* The individual configuration values can be found in the table.
|
|
102
|
+
*
|
|
103
|
+
* @property {Object} templates Template definitions
|
|
104
|
+
* @property {string} templates.main Main template
|
|
105
|
+
* @property {Object} message Message definition
|
|
106
|
+
* @property {string|HTMLElement} message.content The message content
|
|
107
|
+
* @property {string} message.title The message title
|
|
108
|
+
* @property {string} message.icon The message icon
|
|
109
|
+
* @property {Object} message.width Width options for the message popper
|
|
110
|
+
* @property {string|number} message.width.min Minimum width (px, rem, em, vw)
|
|
111
|
+
* @property {string|number} message.width.max Maximum width (px, rem, em, vw)
|
|
112
|
+
* @property {number} message.width.viewportRatio Max width as ratio of viewport width (0-1)
|
|
113
|
+
* @property {string} mode The mode of the button, can be `manual` or `submit`
|
|
114
|
+
* @property {string} labels.button Button label
|
|
115
|
+
* @property {Object} classes Classes for internal elements
|
|
116
|
+
* @property {string} classes.button Button class
|
|
117
|
+
* @property {Object} actions Action callbacks
|
|
118
|
+
* @property {function} actions.click Action triggered on click
|
|
119
|
+
* @property {Object} aria Aria attributes
|
|
120
|
+
* @property {string} aria.role Aria role, only if the button is not a button
|
|
121
|
+
* @property {string} aria.label Aria label for the button
|
|
122
|
+
*/
|
|
123
|
+
get defaults() {
|
|
124
|
+
return Object.assign({}, super.defaults, {
|
|
125
|
+
message: {
|
|
126
|
+
title: undefined,
|
|
127
|
+
content: undefined,
|
|
128
|
+
icon: undefined,
|
|
129
|
+
width: {
|
|
130
|
+
min: "12rem",
|
|
131
|
+
max: "32rem",
|
|
132
|
+
viewportRatio: 0.7,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
templates: {
|
|
136
|
+
main: getTemplate(),
|
|
137
|
+
},
|
|
138
|
+
mode: "manual",
|
|
139
|
+
labels: {
|
|
140
|
+
button: "<slot></slot>",
|
|
141
|
+
},
|
|
142
|
+
classes: {
|
|
143
|
+
button: "monster-button-outline-primary",
|
|
144
|
+
},
|
|
145
|
+
actions: {
|
|
146
|
+
click: (e) => {},
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
aria: {
|
|
150
|
+
role: null,
|
|
151
|
+
label: null,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @return {void}
|
|
158
|
+
*/
|
|
159
|
+
[assembleMethodSymbol]() {
|
|
160
|
+
super[assembleMethodSymbol]();
|
|
161
|
+
initControlReferences.call(this);
|
|
162
|
+
initDisabledSync.call(this);
|
|
163
|
+
|
|
164
|
+
let modes = null;
|
|
165
|
+
const modeOption = this.getOption("mode");
|
|
166
|
+
if (typeof modeOption === "string") {
|
|
167
|
+
modes = modeOption.split(" ");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (
|
|
171
|
+
modes === null ||
|
|
172
|
+
modes === undefined ||
|
|
173
|
+
isArray(modes) === false ||
|
|
174
|
+
modes.length === 0
|
|
175
|
+
) {
|
|
176
|
+
modes = ["manual"];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
for (const [, mode] of Object.entries(modes)) {
|
|
180
|
+
initEventHandlerByMode.call(this, mode);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Sets the message content to be displayed in the popup overlay
|
|
186
|
+
*
|
|
187
|
+
* @param {string|HTMLElement} message - The message content as string or HTML element
|
|
188
|
+
* @param {string} title - Optional title to show above the message
|
|
189
|
+
* @param {string} icon - Optional icon HTML to display next to the title
|
|
190
|
+
* @return {MessageStateButton} Returns the button instance for chaining
|
|
191
|
+
* @throws {TypeError} When message is empty or invalid type
|
|
192
|
+
*/
|
|
193
|
+
setMessage(message, title, icon) {
|
|
194
|
+
if (isString(message)) {
|
|
195
|
+
if (message === "") {
|
|
196
|
+
throw new TypeError("message must not be empty");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const containerDiv = document.createElement("div");
|
|
200
|
+
const messageDiv = document.createElement("div");
|
|
201
|
+
const titleDiv = document.createElement("div");
|
|
202
|
+
titleDiv.setAttribute(ATTRIBUTE_ROLE, "message-title-box");
|
|
203
|
+
|
|
204
|
+
let titleElement, iconElement;
|
|
205
|
+
if (title !== undefined) {
|
|
206
|
+
title = validateString(title);
|
|
207
|
+
titleElement = document.createElement("div");
|
|
208
|
+
titleElement.setAttribute("class", "");
|
|
209
|
+
titleElement.innerHTML = title;
|
|
210
|
+
titleElement.setAttribute(ATTRIBUTE_ROLE, "message-title");
|
|
211
|
+
titleDiv.appendChild(titleElement);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (icon !== undefined) {
|
|
215
|
+
icon = validateString(icon);
|
|
216
|
+
iconElement = document.createElement("div");
|
|
217
|
+
iconElement.setAttribute("class", "");
|
|
218
|
+
iconElement.innerHTML = icon;
|
|
219
|
+
iconElement.setAttribute(ATTRIBUTE_ROLE, "message-icon");
|
|
220
|
+
titleDiv.appendChild(iconElement);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
messageDiv.innerHTML = message;
|
|
224
|
+
containerDiv.appendChild(titleDiv);
|
|
225
|
+
containerDiv.appendChild(messageDiv);
|
|
226
|
+
|
|
227
|
+
this.setOption("message.content", containerDiv);
|
|
228
|
+
} else if (message instanceof HTMLElement) {
|
|
229
|
+
this.setOption("message.content", message);
|
|
230
|
+
} else {
|
|
231
|
+
throw new TypeError(
|
|
232
|
+
"message must be a string or an instance of HTMLElement",
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* clears the Message
|
|
241
|
+
*
|
|
242
|
+
* @return {MessageStateButton}
|
|
243
|
+
*/
|
|
244
|
+
clearMessage() {
|
|
245
|
+
this.setOption("message.title", undefined);
|
|
246
|
+
this.setOption("message.content", undefined);
|
|
247
|
+
this.setOption("message.icon", undefined);
|
|
248
|
+
return this;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Shows the message popup overlay with optional auto-hide timeout
|
|
253
|
+
*
|
|
254
|
+
* @param {number} timeout - Optional time in milliseconds after which the message will auto-hide
|
|
255
|
+
* @return {MessageStateButton} Returns the button instance for chaining
|
|
256
|
+
*/
|
|
257
|
+
showMessage(timeout) {
|
|
258
|
+
applyMeasuredMessageWidth.call(this);
|
|
259
|
+
this.showDialog.call(this);
|
|
260
|
+
|
|
261
|
+
if (timeout !== undefined) {
|
|
262
|
+
setTimeout(() => {
|
|
263
|
+
super.hideDialog();
|
|
264
|
+
}, timeout);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return this;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* With this method, you can show the popper.
|
|
272
|
+
*
|
|
273
|
+
* @return {MessageStateButton}
|
|
274
|
+
*/
|
|
275
|
+
showDialog() {
|
|
276
|
+
if (this.getOption("message.content") === undefined) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
super.showDialog();
|
|
280
|
+
return this;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
*
|
|
285
|
+
* @return {MessageStateButton}
|
|
286
|
+
*/
|
|
287
|
+
hideMessage() {
|
|
288
|
+
super.hideDialog();
|
|
289
|
+
return this;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
*
|
|
294
|
+
* @return {MessageStateButton}
|
|
295
|
+
*/
|
|
296
|
+
toggleMessage() {
|
|
297
|
+
super.toggleDialog();
|
|
298
|
+
return this;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
*
|
|
303
|
+
* @return {Object}
|
|
304
|
+
*/
|
|
305
|
+
getMessage() {
|
|
306
|
+
return this.getOption("message");
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
*
|
|
311
|
+
* @return {string}
|
|
312
|
+
*/
|
|
313
|
+
static getTag() {
|
|
314
|
+
return "monster-message-state-button";
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
*
|
|
319
|
+
* @return {CSSStyleSheet[]}
|
|
320
|
+
*/
|
|
321
|
+
static getCSSStyleSheet() {
|
|
322
|
+
const styles = Popper.getCSSStyleSheet();
|
|
323
|
+
styles.push(StateButtonStyleSheet);
|
|
324
|
+
styles.push(MessageStateButtonStyleSheet);
|
|
325
|
+
return styles;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Programmatically triggers a click event on the button
|
|
330
|
+
* Will not trigger if the button is disabled
|
|
331
|
+
*
|
|
332
|
+
* @since 3.27.0
|
|
333
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click}
|
|
334
|
+
* @fires monster-click
|
|
335
|
+
*/
|
|
336
|
+
click() {
|
|
337
|
+
if (this.getOption("disabled") === true) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (
|
|
342
|
+
this[buttonElementSymbol] &&
|
|
343
|
+
isFunction(this[buttonElementSymbol].click)
|
|
344
|
+
) {
|
|
345
|
+
this[buttonElementSymbol].click();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* The Button.focus() method sets focus on the internal button element.
|
|
351
|
+
*
|
|
352
|
+
* @since 3.27.0
|
|
353
|
+
* @param {Object} options
|
|
354
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus}
|
|
355
|
+
*/
|
|
356
|
+
focus(options) {
|
|
357
|
+
if (this.getOption("disabled") === true) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (
|
|
362
|
+
this[buttonElementSymbol] &&
|
|
363
|
+
isFunction(this[buttonElementSymbol].focus)
|
|
364
|
+
) {
|
|
365
|
+
this[buttonElementSymbol].focus(options);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* The Button.blur() method removes focus from the internal button element.
|
|
371
|
+
*/
|
|
372
|
+
blur() {
|
|
373
|
+
if (
|
|
374
|
+
this[buttonElementSymbol] &&
|
|
375
|
+
isFunction(this[buttonElementSymbol].blur)
|
|
376
|
+
) {
|
|
377
|
+
this[buttonElementSymbol].blur();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
367
380
|
}
|
|
368
381
|
|
|
369
382
|
/**
|
|
@@ -371,27 +384,27 @@ class MessageStateButton extends Popper {
|
|
|
371
384
|
* @param mode
|
|
372
385
|
*/
|
|
373
386
|
function initEventHandlerByMode(mode) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
387
|
+
switch (mode) {
|
|
388
|
+
case "manual":
|
|
389
|
+
this[buttonElementSymbol].setOption("actions.click", (e) => {
|
|
390
|
+
const callback = this.getOption("actions.click");
|
|
391
|
+
if (isFunction(callback)) {
|
|
392
|
+
callback(e);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
break;
|
|
397
|
+
case "submit":
|
|
398
|
+
this[buttonElementSymbol].setOption("actions.click", (e) => {
|
|
399
|
+
const form = this.form;
|
|
400
|
+
|
|
401
|
+
if (form instanceof HTMLFormElement) {
|
|
402
|
+
form.requestSubmit();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
395
408
|
}
|
|
396
409
|
|
|
397
410
|
/**
|
|
@@ -399,83 +412,83 @@ function initEventHandlerByMode(mode) {
|
|
|
399
412
|
* @return {Select}
|
|
400
413
|
*/
|
|
401
414
|
function initControlReferences() {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
415
|
+
this[buttonElementSymbol] = this.shadowRoot.querySelector(
|
|
416
|
+
`[${ATTRIBUTE_ROLE}=button]`,
|
|
417
|
+
);
|
|
418
|
+
this[popperElementSymbol] = this.shadowRoot.querySelector(
|
|
419
|
+
`[${ATTRIBUTE_ROLE}=popper]`,
|
|
420
|
+
);
|
|
421
|
+
this[messageElementSymbol] = this.shadowRoot.querySelector(
|
|
422
|
+
`[${ATTRIBUTE_ROLE}=message]`,
|
|
423
|
+
);
|
|
411
424
|
}
|
|
412
425
|
|
|
413
426
|
/**
|
|
414
427
|
* @private
|
|
415
428
|
*/
|
|
416
429
|
function initDisabledSync() {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
430
|
+
const self = this;
|
|
431
|
+
const attachInnerObserver = (button) => {
|
|
432
|
+
if (!button || !isFunction(button.attachObserver)) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const existing = self[innerDisabledObserverSymbol];
|
|
437
|
+
if (existing?.button === button) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (
|
|
442
|
+
existing?.button &&
|
|
443
|
+
isFunction(existing.button.detachObserver) &&
|
|
444
|
+
existing.observer
|
|
445
|
+
) {
|
|
446
|
+
existing.button.detachObserver(existing.observer);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const observer = new Observer(syncDisabled);
|
|
450
|
+
button.attachObserver(observer);
|
|
451
|
+
self[innerDisabledObserverSymbol] = { button, observer };
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
const syncDisabled = () => {
|
|
455
|
+
const disabled = self.getOption("disabled", false);
|
|
456
|
+
const button =
|
|
457
|
+
self.shadowRoot?.querySelector(`[${ATTRIBUTE_ROLE}=button]`) ??
|
|
458
|
+
self[buttonElementSymbol];
|
|
459
|
+
if (!button) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
self[buttonElementSymbol] = button;
|
|
464
|
+
|
|
465
|
+
if (disabled) {
|
|
466
|
+
button.setAttribute(ATTRIBUTE_DISABLED, "");
|
|
467
|
+
} else {
|
|
468
|
+
button.removeAttribute(ATTRIBUTE_DISABLED);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (isFunction(button.setOption)) {
|
|
472
|
+
button.setOption("disabled", disabled);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
attachInnerObserver(button);
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
syncDisabled();
|
|
479
|
+
const existingObserver = self[attributeObserverSymbol]?.[ATTRIBUTE_DISABLED];
|
|
480
|
+
if (existingObserver) {
|
|
481
|
+
self[attributeObserverSymbol][ATTRIBUTE_DISABLED] = () => {
|
|
482
|
+
existingObserver.call(self);
|
|
483
|
+
syncDisabled();
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
self.attachObserver(new Observer(syncDisabled));
|
|
487
|
+
if (typeof customElements?.whenDefined === "function") {
|
|
488
|
+
customElements.whenDefined("monster-state-button").then(() => {
|
|
489
|
+
syncDisabled();
|
|
490
|
+
});
|
|
491
|
+
}
|
|
479
492
|
}
|
|
480
493
|
|
|
481
494
|
/**
|
|
@@ -483,8 +496,8 @@ function initDisabledSync() {
|
|
|
483
496
|
* @return {string}
|
|
484
497
|
*/
|
|
485
498
|
function getTemplate() {
|
|
486
|
-
|
|
487
|
-
|
|
499
|
+
// language=HTML
|
|
500
|
+
return `
|
|
488
501
|
<div data-monster-role="control" part="control">
|
|
489
502
|
|
|
490
503
|
<monster-state-button exportparts="button:button-button,control:button-control"
|
|
@@ -515,15 +528,15 @@ function getTemplate() {
|
|
|
515
528
|
* @return {HTMLElement|string|null}
|
|
516
529
|
*/
|
|
517
530
|
function getMeasurementContent(content) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
531
|
+
if (isString(content)) {
|
|
532
|
+
return content;
|
|
533
|
+
}
|
|
521
534
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
535
|
+
if (content instanceof HTMLElement) {
|
|
536
|
+
return content.cloneNode(true);
|
|
537
|
+
}
|
|
525
538
|
|
|
526
|
-
|
|
539
|
+
return null;
|
|
527
540
|
}
|
|
528
541
|
|
|
529
542
|
/**
|
|
@@ -531,84 +544,159 @@ function getMeasurementContent(content) {
|
|
|
531
544
|
* @return {{popper: HTMLElement, message: HTMLElement}|null}
|
|
532
545
|
*/
|
|
533
546
|
function ensureMeasurementPopper() {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
547
|
+
if (this[measurementPopperSymbol]) {
|
|
548
|
+
return this[measurementPopperSymbol];
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (!this.shadowRoot) {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const popper = document.createElement("div");
|
|
556
|
+
popper.setAttribute(ATTRIBUTE_ROLE, "popper");
|
|
557
|
+
popper.setAttribute("data-measurement", "true");
|
|
558
|
+
popper.setAttribute("aria-hidden", "true");
|
|
559
|
+
popper.style.position = "absolute";
|
|
560
|
+
popper.style.left = "-10000px";
|
|
561
|
+
popper.style.top = "-10000px";
|
|
562
|
+
popper.style.visibility = "hidden";
|
|
563
|
+
popper.style.display = "block";
|
|
564
|
+
popper.style.pointerEvents = "none";
|
|
565
|
+
popper.style.maxWidth = "none";
|
|
566
|
+
popper.style.width = "max-content";
|
|
567
|
+
if (this[popperElementSymbol]?.className) {
|
|
568
|
+
popper.className = this[popperElementSymbol].className;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const message = document.createElement("div");
|
|
572
|
+
message.setAttribute(ATTRIBUTE_ROLE, "message");
|
|
573
|
+
message.className = "flex";
|
|
574
|
+
|
|
575
|
+
popper.appendChild(message);
|
|
576
|
+
this.shadowRoot.appendChild(popper);
|
|
577
|
+
|
|
578
|
+
this[measurementPopperSymbol] = { popper, message };
|
|
579
|
+
return this[measurementPopperSymbol];
|
|
564
580
|
}
|
|
565
581
|
|
|
566
582
|
/**
|
|
567
583
|
* @private
|
|
568
584
|
*/
|
|
569
585
|
function applyMeasuredMessageWidth() {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
586
|
+
const popper = this[popperElementSymbol];
|
|
587
|
+
if (!popper) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const content = this.getOption("message.content");
|
|
592
|
+
const measureContent = getMeasurementContent(content);
|
|
593
|
+
if (!measureContent) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const measurement = ensureMeasurementPopper.call(this);
|
|
598
|
+
if (!measurement?.message) {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (popper.className && measurement.popper.className !== popper.className) {
|
|
603
|
+
measurement.popper.className = popper.className;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
measurement.message.innerHTML = "";
|
|
607
|
+
if (isString(measureContent)) {
|
|
608
|
+
measurement.message.innerHTML = measureContent;
|
|
609
|
+
} else {
|
|
610
|
+
measurement.message.appendChild(measureContent);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const measuredWidth = Math.ceil(
|
|
614
|
+
measurement.popper.getBoundingClientRect().width,
|
|
615
|
+
);
|
|
616
|
+
const fontSize = parseFloat(getComputedStyle(popper).fontSize) || 16;
|
|
617
|
+
const rootFontSize =
|
|
618
|
+
parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
619
|
+
const widthOptions = this.getOption("message.width", {});
|
|
620
|
+
const minWidthOption = resolveLength(
|
|
621
|
+
widthOptions?.min,
|
|
622
|
+
fontSize,
|
|
623
|
+
rootFontSize,
|
|
624
|
+
window.innerWidth,
|
|
625
|
+
);
|
|
626
|
+
const maxWidthOption = resolveLength(
|
|
627
|
+
widthOptions?.max,
|
|
628
|
+
fontSize,
|
|
629
|
+
rootFontSize,
|
|
630
|
+
window.innerWidth,
|
|
631
|
+
);
|
|
632
|
+
const viewportRatio =
|
|
633
|
+
typeof widthOptions?.viewportRatio === "number" &&
|
|
634
|
+
widthOptions.viewportRatio > 0 &&
|
|
635
|
+
widthOptions.viewportRatio <= 1
|
|
636
|
+
? widthOptions.viewportRatio
|
|
637
|
+
: 0.7;
|
|
638
|
+
|
|
639
|
+
const minWidth = Math.max(0, minWidthOption ?? Math.round(fontSize * 12));
|
|
640
|
+
const maxViewportWidth = Math.max(
|
|
641
|
+
minWidth,
|
|
642
|
+
window.innerWidth * viewportRatio,
|
|
643
|
+
);
|
|
644
|
+
const maxWidth = Math.max(
|
|
645
|
+
minWidth,
|
|
646
|
+
Math.min(maxWidthOption ?? fontSize * 32, maxViewportWidth),
|
|
647
|
+
);
|
|
648
|
+
const targetWidth = Math.max(
|
|
649
|
+
minWidth,
|
|
650
|
+
Math.min(measuredWidth || minWidth, maxWidth),
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
popper.style.width = `${targetWidth}px`;
|
|
654
|
+
popper.style.minWidth = `${minWidth}px`;
|
|
655
|
+
popper.style.maxWidth = `${maxWidth}px`;
|
|
656
|
+
popper.style.whiteSpace = "normal";
|
|
657
|
+
popper.style.overflowWrap = "anywhere";
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* @private
|
|
662
|
+
* @param {unknown} value
|
|
663
|
+
* @param {number} fontSize
|
|
664
|
+
* @param {number} rootFontSize
|
|
665
|
+
* @param {number} viewportWidth
|
|
666
|
+
* @return {number|null}
|
|
667
|
+
*/
|
|
668
|
+
function resolveLength(value, fontSize, rootFontSize, viewportWidth) {
|
|
669
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
670
|
+
return value;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (!isString(value)) {
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const trimmed = value.trim();
|
|
678
|
+
const number = parseFloat(trimmed);
|
|
679
|
+
if (!Number.isFinite(number)) {
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (trimmed.endsWith("rem")) {
|
|
684
|
+
return number * rootFontSize;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (trimmed.endsWith("em")) {
|
|
688
|
+
return number * fontSize;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if (trimmed.endsWith("vw")) {
|
|
692
|
+
return (number / 100) * viewportWidth;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (trimmed.endsWith("px")) {
|
|
696
|
+
return number;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
return number;
|
|
612
700
|
}
|
|
613
701
|
|
|
614
702
|
registerCustomElement(MessageStateButton);
|
|
@@ -72,6 +72,7 @@ class Panel extends CustomElement {
|
|
|
72
72
|
* @property {Object} templates Template definitions
|
|
73
73
|
* @property {string} templates.main Main template
|
|
74
74
|
* @property {string} heightAdjustment Height adjustment
|
|
75
|
+
* @property {string} controlOverflow Overflow value applied to the control element
|
|
75
76
|
*/
|
|
76
77
|
get defaults() {
|
|
77
78
|
return Object.assign({}, super.defaults, {
|
|
@@ -79,6 +80,7 @@ class Panel extends CustomElement {
|
|
|
79
80
|
main: getTemplate(),
|
|
80
81
|
},
|
|
81
82
|
heightAdjustment: 4,
|
|
83
|
+
controlOverflow: "auto",
|
|
82
84
|
});
|
|
83
85
|
}
|
|
84
86
|
|
|
@@ -91,6 +93,7 @@ class Panel extends CustomElement {
|
|
|
91
93
|
|
|
92
94
|
initControlReferences.call(this);
|
|
93
95
|
initEventHandler.call(this);
|
|
96
|
+
applyControlOverflow.call(this);
|
|
94
97
|
|
|
95
98
|
calcHeight.call(this);
|
|
96
99
|
}
|
|
@@ -272,6 +275,24 @@ function initEventHandler() {
|
|
|
272
275
|
return this;
|
|
273
276
|
}
|
|
274
277
|
|
|
278
|
+
/**
|
|
279
|
+
* @private
|
|
280
|
+
*/
|
|
281
|
+
function applyControlOverflow() {
|
|
282
|
+
const control = this[PanelElementSymbol];
|
|
283
|
+
if (!(control instanceof HTMLElement)) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const overflow = this.getOption("controlOverflow");
|
|
288
|
+
if (overflow === null || overflow === undefined || overflow === "") {
|
|
289
|
+
control.style.removeProperty("overflow");
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
control.style.overflow = overflow;
|
|
294
|
+
}
|
|
295
|
+
|
|
275
296
|
/**
|
|
276
297
|
* @private
|
|
277
298
|
* @return {string}
|