@schukai/monster 4.10.4 → 4.11.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 +8 -0
- package/package.json +1 -1
- package/source/components/data/metric-graph.mjs +475 -0
- package/source/components/data/metric.mjs +187 -0
- package/source/components/data/style/metric-graph.pcss +71 -0
- package/source/components/data/style/metric.pcss +88 -0
- package/source/components/data/stylesheet/metric-graph.mjs +31 -0
- package/source/components/data/stylesheet/metric.mjs +31 -0
- package/source/components/style/typography.css +2 -4
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.0","@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":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.0","@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.11.0"}
|
@@ -0,0 +1,475 @@
|
|
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 {addAttributeToken} from "../../dom/attributes.mjs";
|
15
|
+
import {
|
16
|
+
ATTRIBUTE_ERRORMESSAGE,
|
17
|
+
ATTRIBUTE_ROLE,
|
18
|
+
} from "../../dom/constants.mjs";
|
19
|
+
import {CustomElement, updaterTransformerMethodsSymbol} from "../../dom/customelement.mjs";
|
20
|
+
import {
|
21
|
+
assembleMethodSymbol,
|
22
|
+
registerCustomElement,
|
23
|
+
} from "../../dom/customelement.mjs";
|
24
|
+
import {findTargetElementFromEvent} from "../../dom/events.mjs";
|
25
|
+
import {isFunction, isString} from "../../types/is.mjs";
|
26
|
+
import {MetricGraphStyleSheet} from "./stylesheet/metric-graph.mjs";
|
27
|
+
import {fireCustomEvent} from "../../dom/events.mjs";
|
28
|
+
|
29
|
+
|
30
|
+
export {MetricGraph};
|
31
|
+
|
32
|
+
/**
|
33
|
+
* @private
|
34
|
+
* @type {symbol}
|
35
|
+
*/
|
36
|
+
export const metricGraphControlElementSymbol = Symbol("metricGraphControlElement");
|
37
|
+
|
38
|
+
/**
|
39
|
+
* A MetricGraph
|
40
|
+
*
|
41
|
+
* @fragments /fragments/data/metric-graph/
|
42
|
+
*
|
43
|
+
* @example /examples/data/metric-graph-simple
|
44
|
+
*
|
45
|
+
* @since 4.11.0
|
46
|
+
* @copyright schukai GmbH
|
47
|
+
* @summary A beautiful MetricGraph that can make your life easier and also looks good.
|
48
|
+
*/
|
49
|
+
class MetricGraph extends CustomElement {
|
50
|
+
/**
|
51
|
+
* This method is called by the `instanceof` operator.
|
52
|
+
* @returns {symbol}
|
53
|
+
*/
|
54
|
+
static get [instanceSymbol]() {
|
55
|
+
return Symbol.for("@schukai/monster/data/metric-graph@@instance");
|
56
|
+
}
|
57
|
+
|
58
|
+
/**
|
59
|
+
* @return {Components.Data.Metric
|
60
|
+
*/
|
61
|
+
[assembleMethodSymbol]() {
|
62
|
+
super[assembleMethodSymbol]();
|
63
|
+
initControlReferences.call(this);
|
64
|
+
return this;
|
65
|
+
}
|
66
|
+
|
67
|
+
/**
|
68
|
+
* To set the options via the HTML Tag, the attribute `data-monster-options` must be used.
|
69
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
70
|
+
*
|
71
|
+
* The individual configuration values can be found in the table.
|
72
|
+
*
|
73
|
+
* @property {Object} templates Template definitions
|
74
|
+
* @property {string} templates.main Main template
|
75
|
+
* @property {string} curve The curve of the graph (step, smooth, bubble, bar, area, dot, lollipop, line)
|
76
|
+
* @property {Object} values Value definitions
|
77
|
+
* @property {number} values.value The value of the metric
|
78
|
+
* @property {number} values.change The change of the metric
|
79
|
+
* @property {number} values.secondary The secondary value of the metric
|
80
|
+
* @property {Array} values.points The points of the metric
|
81
|
+
* @property {Object} labels Label definitions
|
82
|
+
* @property {string} labels.title Title of the metric
|
83
|
+
* @property {string} labels.subtext Subtext of the metric
|
84
|
+
* @property {Object} classes CSS classes
|
85
|
+
* @property {string} classes.dot CSS class for the dot
|
86
|
+
*/
|
87
|
+
get defaults() {
|
88
|
+
return Object.assign({}, super.defaults, {
|
89
|
+
templates: {
|
90
|
+
main: getTemplate(),
|
91
|
+
},
|
92
|
+
|
93
|
+
graphType: "linear",
|
94
|
+
|
95
|
+
values: {
|
96
|
+
main: null,
|
97
|
+
change: null,
|
98
|
+
secondary: null,
|
99
|
+
points: [2, 2, 2, -30, 30, 5, 4,4, 3, 3, 2,2, 1, 1, 1, 1],
|
100
|
+
},
|
101
|
+
labels: {
|
102
|
+
title: null,
|
103
|
+
subtext: null,
|
104
|
+
|
105
|
+
},
|
106
|
+
classes: {
|
107
|
+
dot: "monster-theme-primary-1"
|
108
|
+
},
|
109
|
+
|
110
|
+
aria : {
|
111
|
+
description: null,
|
112
|
+
}
|
113
|
+
|
114
|
+
});
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
/**
|
119
|
+
*
|
120
|
+
* @returns {{tosparkline: ((function(*): (string|string))|*)}}
|
121
|
+
*/
|
122
|
+
[updaterTransformerMethodsSymbol]() {
|
123
|
+
|
124
|
+
return {
|
125
|
+
"toGraph": (value) => {
|
126
|
+
if (isString(value)) {
|
127
|
+
value = value.split(",").map((v) => {
|
128
|
+
return parseFloat(v);
|
129
|
+
});
|
130
|
+
}
|
131
|
+
|
132
|
+
const graphType = this.getOption("graphType");
|
133
|
+
|
134
|
+
if (!Array.isArray(value) || value.length === 0) return "";
|
135
|
+
switch (graphType.toLowerCase()) {
|
136
|
+
case "step":
|
137
|
+
return renderStepGraph.call(this, value);
|
138
|
+
case "smooth":
|
139
|
+
return renderSmoothGraph.call(this, value);
|
140
|
+
case "bubble":
|
141
|
+
return renderBubbleGraph.call(this, value);
|
142
|
+
case "bar":
|
143
|
+
return renderBarGraph.call(this, value);
|
144
|
+
case "area":
|
145
|
+
return renderAreaGraph.call(this, value);
|
146
|
+
case "dot":
|
147
|
+
return renderDotGraph.call(this, value);
|
148
|
+
case "lollipop":
|
149
|
+
return renderLollipopGraph.call(this, value);
|
150
|
+
case "line":
|
151
|
+
default:
|
152
|
+
return renderLineGraph.call(this, value);
|
153
|
+
}
|
154
|
+
|
155
|
+
}
|
156
|
+
};
|
157
|
+
}
|
158
|
+
|
159
|
+
/**
|
160
|
+
* @return {string}
|
161
|
+
*/
|
162
|
+
static getTag() {
|
163
|
+
return "monster-metric-graph";
|
164
|
+
}
|
165
|
+
|
166
|
+
/**
|
167
|
+
* @return {CSSStyleSheet[]}
|
168
|
+
*/
|
169
|
+
static getCSSStyleSheet() {
|
170
|
+
return [MetricGraphStyleSheet];
|
171
|
+
}
|
172
|
+
|
173
|
+
|
174
|
+
}
|
175
|
+
|
176
|
+
function renderAreaGraph(values, options = {}) {
|
177
|
+
const {
|
178
|
+
width = 100,
|
179
|
+
height = 30,
|
180
|
+
stroke = "currentColor",
|
181
|
+
strokeWidth = 2,
|
182
|
+
fill = "rgba(0, 0, 0, 0.1)",
|
183
|
+
} = options;
|
184
|
+
|
185
|
+
if (!Array.isArray(values) || values.length === 0) return "";
|
186
|
+
|
187
|
+
const min = Math.min(...values);
|
188
|
+
const max = Math.max(...values);
|
189
|
+
const range = max - min || 1;
|
190
|
+
|
191
|
+
const step = width / (values.length - 1);
|
192
|
+
const points = values.map((v, i) => {
|
193
|
+
const x = i * step;
|
194
|
+
const y = height - ((v - min) / range) * height;
|
195
|
+
return { x, y };
|
196
|
+
});
|
197
|
+
|
198
|
+
let d = `M ${points[0].x},${height} L ${points[0].x},${points[0].y}`;
|
199
|
+
for (let i = 1; i < points.length; i++) {
|
200
|
+
d += ` L ${points[i].x},${points[i].y}`;
|
201
|
+
}
|
202
|
+
d += ` L ${points[points.length - 1].x},${height} Z`;
|
203
|
+
|
204
|
+
return `<path d="${d}" stroke="${stroke}" stroke-width="${strokeWidth}" fill="${fill}" stroke-linejoin="round" />`;
|
205
|
+
}
|
206
|
+
|
207
|
+
function renderBubbleGraph(values, options = {}) {
|
208
|
+
const {
|
209
|
+
width = 100,
|
210
|
+
height = 30,
|
211
|
+
minRadius = 2,
|
212
|
+
maxRadius = 8,
|
213
|
+
lightRange = [0.3, 1.0], // fill-opacity von 0.3 bis 1.0
|
214
|
+
align = "middle",
|
215
|
+
} = options;
|
216
|
+
|
217
|
+
if (!Array.isArray(values) || values.length === 0) return "";
|
218
|
+
|
219
|
+
const min = Math.min(...values);
|
220
|
+
const max = Math.max(...values);
|
221
|
+
const range = max - min || 1;
|
222
|
+
|
223
|
+
const stepX = width / values.length;
|
224
|
+
|
225
|
+
let centerY;
|
226
|
+
switch (align) {
|
227
|
+
case "top": centerY = maxRadius; break;
|
228
|
+
case "bottom": centerY = height - maxRadius; break;
|
229
|
+
case "middle":
|
230
|
+
default: centerY = height / 2;
|
231
|
+
}
|
232
|
+
|
233
|
+
return values.map((v, i) => {
|
234
|
+
const x = i * stepX + stepX / 2;
|
235
|
+
const norm = (v - min) / range;
|
236
|
+
const r = minRadius + norm * (maxRadius - minRadius);
|
237
|
+
const opacity = lightRange[0] + norm * (lightRange[1] - lightRange[0]);
|
238
|
+
|
239
|
+
return `<circle cx="${x.toFixed(2)}" cy="${centerY.toFixed(2)}" r="${r.toFixed(2)}" fill="currentColor" fill-opacity="${opacity.toFixed(2)}" />`;
|
240
|
+
}).join("");
|
241
|
+
}
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
|
246
|
+
function renderLollipopGraph(values, options = {}) {
|
247
|
+
const {
|
248
|
+
width = 100,
|
249
|
+
height = 30,
|
250
|
+
color = "currentColor",
|
251
|
+
radius = 2,
|
252
|
+
strokeWidth = 1,
|
253
|
+
} = options;
|
254
|
+
|
255
|
+
if (!Array.isArray(values) || values.length === 0) return "";
|
256
|
+
|
257
|
+
const min = Math.min(...values);
|
258
|
+
const max = Math.max(...values);
|
259
|
+
const range = max - min || 1;
|
260
|
+
|
261
|
+
const step = width / (values.length - 1);
|
262
|
+
|
263
|
+
return values.map((v, i) => {
|
264
|
+
const x = i * step;
|
265
|
+
const y = height - ((v - min) / range) * height;
|
266
|
+
const line = `<line x1="${x}" y1="${height}" x2="${x}" y2="${y}" stroke="${color}" stroke-width="${strokeWidth}" />`;
|
267
|
+
const circle = `<circle cx="${x}" cy="${y}" r="${radius}" fill="${color}" />`;
|
268
|
+
return line + circle;
|
269
|
+
}).join("");
|
270
|
+
}
|
271
|
+
|
272
|
+
|
273
|
+
function renderDotGraph(values, options = {}) {
|
274
|
+
const {
|
275
|
+
width = 100,
|
276
|
+
height = 30,
|
277
|
+
radius = 2,
|
278
|
+
color = "currentColor",
|
279
|
+
} = options;
|
280
|
+
|
281
|
+
if (!Array.isArray(values) || values.length === 0) return "";
|
282
|
+
|
283
|
+
const min = Math.min(...values);
|
284
|
+
const max = Math.max(...values);
|
285
|
+
const range = max - min || 1;
|
286
|
+
|
287
|
+
const step = width / (values.length - 1);
|
288
|
+
|
289
|
+
return values.map((v, i) => {
|
290
|
+
const x = i * step;
|
291
|
+
const y = height - ((v - min) / range) * height;
|
292
|
+
return `<circle cx="${x.toFixed(2)}" cy="${y.toFixed(2)}" r="${radius}" fill="${color}" />`;
|
293
|
+
}).join("");
|
294
|
+
}
|
295
|
+
|
296
|
+
|
297
|
+
|
298
|
+
function renderBarGraph(values, options = {}) {
|
299
|
+
const {
|
300
|
+
width = 100,
|
301
|
+
height = 30,
|
302
|
+
barColor = "currentColor",
|
303
|
+
barSpacing = 1,
|
304
|
+
} = options;
|
305
|
+
|
306
|
+
if (!Array.isArray(values) || values.length === 0) return "";
|
307
|
+
|
308
|
+
const min = Math.min(...values);
|
309
|
+
const max = Math.max(...values);
|
310
|
+
const range = max - min || 1;
|
311
|
+
|
312
|
+
const barWidth = width / values.length - barSpacing;
|
313
|
+
|
314
|
+
return values
|
315
|
+
.map((v, i) => {
|
316
|
+
const x = i * (barWidth + barSpacing);
|
317
|
+
const barHeight = ((v - min) / range) * height;
|
318
|
+
const y = height - barHeight;
|
319
|
+
return `<rect x="${x.toFixed(2)}" y="${y.toFixed(2)}" width="${barWidth.toFixed(2)}" height="${barHeight.toFixed(2)}" fill="${barColor}" />`;
|
320
|
+
})
|
321
|
+
.join("");
|
322
|
+
}
|
323
|
+
|
324
|
+
function renderLineGraph(values) {
|
325
|
+
if (!Array.isArray(values) || values.length === 0) return "";
|
326
|
+
const min = Math.min(...values);
|
327
|
+
const max = Math.max(...values);
|
328
|
+
const range = max - min || 1;
|
329
|
+
|
330
|
+
const step = 100 / (values.length - 1);
|
331
|
+
const points = values.map((v, i) => {
|
332
|
+
const x = i * step;
|
333
|
+
const y = 30 - ((v - min) / range) * 30;
|
334
|
+
return `${x},${y}`;
|
335
|
+
});
|
336
|
+
|
337
|
+
return `<polyline points="${points.join(" ")}" stroke="currentColor" stroke-width="2" fill="none" />`;
|
338
|
+
}
|
339
|
+
|
340
|
+
function renderSmoothGraph(values, options = {}) {
|
341
|
+
const {
|
342
|
+
width = 100,
|
343
|
+
height = 30,
|
344
|
+
stroke = "currentColor",
|
345
|
+
strokeWidth = 2,
|
346
|
+
fill = "none",
|
347
|
+
} = options;
|
348
|
+
|
349
|
+
if (!Array.isArray(values) || values.length === 0) return "";
|
350
|
+
|
351
|
+
const min = Math.min(...values);
|
352
|
+
const max = Math.max(...values);
|
353
|
+
const range = max - min || 1;
|
354
|
+
|
355
|
+
const stepX = width / (values.length - 1);
|
356
|
+
|
357
|
+
const points = values.map((v, i) => {
|
358
|
+
const x = i * stepX;
|
359
|
+
const y = height - ((v - min) / range) * height;
|
360
|
+
return { x, y };
|
361
|
+
});
|
362
|
+
|
363
|
+
// Bézier-Path erzeugen
|
364
|
+
let d = `M ${points[0].x},${points[0].y}`;
|
365
|
+
for (let i = 1; i < points.length; i++) {
|
366
|
+
const prev = points[i - 1];
|
367
|
+
const curr = points[i];
|
368
|
+
const cx = (prev.x + curr.x) / 2;
|
369
|
+
d += ` Q ${prev.x},${prev.y} ${cx},${(prev.y + curr.y) / 2}`;
|
370
|
+
}
|
371
|
+
d += ` T ${points[points.length - 1].x},${points[points.length - 1].y}`;
|
372
|
+
|
373
|
+
return `<path d="${d}" stroke="${stroke}" stroke-width="${strokeWidth}" fill="${fill}" stroke-linecap="round" stroke-linejoin="round" />`;
|
374
|
+
}
|
375
|
+
|
376
|
+
function renderStepGraph(values, options = {}) {
|
377
|
+
const {
|
378
|
+
width = 100,
|
379
|
+
height = 30,
|
380
|
+
stroke = "currentColor",
|
381
|
+
strokeWidth = 2,
|
382
|
+
fill = "none",
|
383
|
+
} = options;
|
384
|
+
|
385
|
+
if (!Array.isArray(values) || values.length === 0) return "";
|
386
|
+
|
387
|
+
const min = Math.min(...values);
|
388
|
+
const max = Math.max(...values);
|
389
|
+
const range = max - min || 1;
|
390
|
+
|
391
|
+
const stepX = width / (values.length - 1);
|
392
|
+
|
393
|
+
const points = values.map((v, i) => {
|
394
|
+
const x = i * stepX;
|
395
|
+
const y = height - ((v - min) / range) * height;
|
396
|
+
return { x, y };
|
397
|
+
});
|
398
|
+
|
399
|
+
let d = `M ${points[0].x},${points[0].y}`;
|
400
|
+
for (let i = 1; i < points.length; i++) {
|
401
|
+
const prev = points[i - 1];
|
402
|
+
const curr = points[i];
|
403
|
+
d += ` H ${curr.x} V ${curr.y}`;
|
404
|
+
}
|
405
|
+
|
406
|
+
return `<path d="${d}" stroke="${stroke}" stroke-width="${strokeWidth}" fill="${fill}" stroke-linecap="round" stroke-linejoin="round" />`;
|
407
|
+
}
|
408
|
+
|
409
|
+
|
410
|
+
/**
|
411
|
+
* @private
|
412
|
+
* @return {void}
|
413
|
+
*/
|
414
|
+
function initControlReferences() {
|
415
|
+
this[metricGraphControlElementSymbol] = this.shadowRoot.querySelector(
|
416
|
+
`[${ATTRIBUTE_ROLE}="control"]`,
|
417
|
+
);
|
418
|
+
}
|
419
|
+
|
420
|
+
|
421
|
+
/**
|
422
|
+
* @private
|
423
|
+
* @return {string}
|
424
|
+
*/
|
425
|
+
function getTemplate() {
|
426
|
+
// language=HTML
|
427
|
+
return `
|
428
|
+
<div data-monster-role="control"
|
429
|
+
part="control"
|
430
|
+
role="group"
|
431
|
+
aria-labelledby="metric-title"
|
432
|
+
aria-describedby="metric-value metric-subtext metric-graph-desc">
|
433
|
+
|
434
|
+
<div class="metric-card" part="card">
|
435
|
+
<div class="metric-header" part="header">
|
436
|
+
<span data-monster-attributes="class path:classes.dot | prefix:metric-icon\\ :"></span>
|
437
|
+
<span id="metric-title" class="metric-title"
|
438
|
+
data-monster-replace="path:labels.title | ??:—"></span>
|
439
|
+
</div>
|
440
|
+
|
441
|
+
<div id="metric-value" class="metric-value"
|
442
|
+
data-monster-replace="path:values.main"
|
443
|
+
part="metric-value"
|
444
|
+
aria-live="polite">—</div>
|
445
|
+
|
446
|
+
<div id="metric-subtext" class="metric-subtext" part="metric-subtext">
|
447
|
+
<span data-monster-replace="path:labels.subtext | ??:— ">—</span><br>
|
448
|
+
<span class="metric-subtext-value">
|
449
|
+
<strong data-monster-replace="path:values.secondary | ??:—">—</strong>
|
450
|
+
</span>
|
451
|
+
</div>
|
452
|
+
|
453
|
+
<div part="metric-graph" class="metric-graph">
|
454
|
+
<svg viewBox="0 0 100 30"
|
455
|
+
preserveAspectRatio="none"
|
456
|
+
role="img"
|
457
|
+
aria-labelledby="metric-graph-desc"
|
458
|
+
focusable="false"
|
459
|
+
xmlns="http://www.w3.org/2000/svg"
|
460
|
+
data-monster-replace="path:values.points | call:toGraph">
|
461
|
+
</svg>
|
462
|
+
<span id="metric-graph-desc" class="visually-hidden"
|
463
|
+
data-monster-replace="path:aria.graph | ??:Graphische Darstellung der Kennzahl">
|
464
|
+
Graphische Darstellung
|
465
|
+
</span>
|
466
|
+
</div>
|
467
|
+
</div>
|
468
|
+
|
469
|
+
<span class="visually-hidden" data-monster-replace="path:aria.description"></span>
|
470
|
+
</div>`;
|
471
|
+
}
|
472
|
+
|
473
|
+
|
474
|
+
|
475
|
+
registerCustomElement(MetricGraph);
|
@@ -0,0 +1,187 @@
|
|
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 {addAttributeToken} from "../../dom/attributes.mjs";
|
15
|
+
import {
|
16
|
+
ATTRIBUTE_ERRORMESSAGE,
|
17
|
+
ATTRIBUTE_ROLE,
|
18
|
+
} from "../../dom/constants.mjs";
|
19
|
+
import {CustomControl} from "../../dom/customcontrol.mjs";
|
20
|
+
import {CustomElement} from "../../dom/customelement.mjs";
|
21
|
+
import {
|
22
|
+
assembleMethodSymbol,
|
23
|
+
registerCustomElement,
|
24
|
+
} from "../../dom/customelement.mjs";
|
25
|
+
import {findTargetElementFromEvent} from "../../dom/events.mjs";
|
26
|
+
import {isFunction} from "../../types/is.mjs";
|
27
|
+
import {MetricStyleSheet} from "./stylesheet/metric.mjs";
|
28
|
+
import {fireCustomEvent} from "../../dom/events.mjs";
|
29
|
+
|
30
|
+
export {Metric};
|
31
|
+
|
32
|
+
/**
|
33
|
+
* @private
|
34
|
+
* @type {symbol}
|
35
|
+
*/
|
36
|
+
export const metricControlElementSymbol = Symbol("metricControlElement");
|
37
|
+
|
38
|
+
/**
|
39
|
+
* A Metric is a simple component that can be used to display a value.
|
40
|
+
*
|
41
|
+
* @fragments /fragments/components/data/metric/
|
42
|
+
*
|
43
|
+
* @example /examples/components/data/metric-simple
|
44
|
+
*
|
45
|
+
* @since 4.11.0
|
46
|
+
* @copyright schukai GmbH
|
47
|
+
* @summary A beautiful Metric that can make your life easier and also looks good.
|
48
|
+
*/
|
49
|
+
class Metric extends CustomElement {
|
50
|
+
/**
|
51
|
+
* This method is called by the `instanceof` operator.
|
52
|
+
* @returns {symbol}
|
53
|
+
*/
|
54
|
+
static get [instanceSymbol]() {
|
55
|
+
return Symbol.for("@schukai/monster/components/data/metric@@instance");
|
56
|
+
}
|
57
|
+
|
58
|
+
/**
|
59
|
+
* @return {Components.Data.Metric
|
60
|
+
*/
|
61
|
+
[assembleMethodSymbol]() {
|
62
|
+
super[assembleMethodSymbol]();
|
63
|
+
initControlReferences.call(this);
|
64
|
+
return this;
|
65
|
+
}
|
66
|
+
|
67
|
+
/**
|
68
|
+
* To set the options via the HTML Tag, the attribute `data-monster-options` must be used.
|
69
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
70
|
+
*
|
71
|
+
* The individual configuration values can be found in the table.
|
72
|
+
*
|
73
|
+
* @property {Object} templates Template definitions
|
74
|
+
* @property {string} templates.main Main template
|
75
|
+
* @property {Object} values Value definitions
|
76
|
+
* @property {number} values.value The value of the metric
|
77
|
+
* @property {number} values.change The change of the metric
|
78
|
+
* @property {number} values.direction The direction of the metric
|
79
|
+
* @property {number} values.secondary The secondary value of the metric
|
80
|
+
* @property {Object} labels Label definitions
|
81
|
+
* @property {string} labels.title Title of the metric
|
82
|
+
* @property {string} labels.subtext Subtext of the metric
|
83
|
+
* @property {Object} classes CSS classes
|
84
|
+
* @property {string} classes.dot CSS class for the dot
|
85
|
+
* @property {string} classes.metricChange CSS class for the metric change (positive/negative)
|
86
|
+
*/
|
87
|
+
get defaults() {
|
88
|
+
return Object.assign({}, super.defaults, {
|
89
|
+
templates: {
|
90
|
+
main: getTemplate(),
|
91
|
+
},
|
92
|
+
values: {
|
93
|
+
main: null,
|
94
|
+
change: null,
|
95
|
+
direction: 270,
|
96
|
+
secondary: null,
|
97
|
+
},
|
98
|
+
labels: {
|
99
|
+
title: null,
|
100
|
+
subtext: null,
|
101
|
+
},
|
102
|
+
classes: {
|
103
|
+
dot: "monster-theme-primary-1",
|
104
|
+
change: "positive",
|
105
|
+
},
|
106
|
+
|
107
|
+
aria: {
|
108
|
+
description: null,
|
109
|
+
}
|
110
|
+
});
|
111
|
+
}
|
112
|
+
|
113
|
+
/**
|
114
|
+
* @return {string}
|
115
|
+
*/
|
116
|
+
static getTag() {
|
117
|
+
return "monster-metric";
|
118
|
+
}
|
119
|
+
|
120
|
+
/**
|
121
|
+
* @return {CSSStyleSheet[]}
|
122
|
+
*/
|
123
|
+
static getCSSStyleSheet() {
|
124
|
+
return [MetricStyleSheet];
|
125
|
+
}
|
126
|
+
|
127
|
+
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
* @private
|
132
|
+
* @return {void}
|
133
|
+
*/
|
134
|
+
function initControlReferences() {
|
135
|
+
this[metricControlElementSymbol] = this.shadowRoot.querySelector(
|
136
|
+
`[${ATTRIBUTE_ROLE}="control"]`,
|
137
|
+
);
|
138
|
+
}
|
139
|
+
|
140
|
+
/**
|
141
|
+
* @private
|
142
|
+
* @return {string}
|
143
|
+
*/
|
144
|
+
function getTemplate() {
|
145
|
+
// language=HTML
|
146
|
+
return `
|
147
|
+
<div data-monster-role="control" part="control"
|
148
|
+
role="group"
|
149
|
+
aria-labelledby="metric-title"
|
150
|
+
aria-describedby="metric-subtext metric-value metric-change-text">
|
151
|
+
|
152
|
+
<div class="metric-card" part="card">
|
153
|
+
<div class="metric-header" part="header">
|
154
|
+
<span data-monster-attributes="class path:classes.dot | prefix:metric-icon\\ :"></span>
|
155
|
+
<span id="metric-title" class="metric-title"
|
156
|
+
data-monster-replace="path:labels.title | ??:—"></span>
|
157
|
+
</div>
|
158
|
+
|
159
|
+
<div id="metric-value" class="metric-value"
|
160
|
+
data-monster-replace="path:values.main" part="metric-value">—</div>
|
161
|
+
|
162
|
+
<div id="metric-subtext" class="metric-subtext" part="metric-subtext">
|
163
|
+
<span data-monster-replace="path:labels.subtext | ??:— ">—</span><br>
|
164
|
+
<span class="metric-subtext-value">
|
165
|
+
<strong data-monster-replace="path:values.secondary | ??:—">—</strong>
|
166
|
+
</span>
|
167
|
+
</div>
|
168
|
+
|
169
|
+
<div id="metric-change-text" part="metric-change"
|
170
|
+
data-monster-attributes="style path:values.direction | tostring | prefix:--arrow-direction\\:\\ : | suffix:deg,
|
171
|
+
class path:classes.change | prefix:metric-change\\ :">
|
172
|
+
<span class="arrow">
|
173
|
+
<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
174
|
+
<path d="M12 4v16m0 0l-6-6m6 6l6-6"
|
175
|
+
stroke="currentColor" stroke-width="2"
|
176
|
+
fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
177
|
+
</svg>
|
178
|
+
</span>
|
179
|
+
<span data-monster-replace="path:values.change | ??:—"></span>
|
180
|
+
</div>
|
181
|
+
</div>
|
182
|
+
|
183
|
+
<span class="visually-hidden" data-monster-replace="path:aria.description"></span>
|
184
|
+
</div>`;
|
185
|
+
}
|
186
|
+
|
187
|
+
registerCustomElement(Metric);
|