@schukai/monster 4.40.0 → 4.41.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 +23 -0
- package/package.json +1 -1
- package/source/components/datatable/datatable.mjs +1204 -1180
- package/source/components/form/quantity.mjs +336 -0
- package/source/components/form/select.mjs +1 -3
- package/source/components/form/style/quantity.pcss +150 -0
- package/source/components/form/stylesheet/quantity.mjs +31 -0
@@ -0,0 +1,336 @@
|
|
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 { CustomControl } from "../../dom/customcontrol.mjs";
|
16
|
+
import {
|
17
|
+
assembleMethodSymbol,
|
18
|
+
registerCustomElement,
|
19
|
+
} from "../../dom/customelement.mjs";
|
20
|
+
import { fireCustomEvent } from "../../dom/events.mjs";
|
21
|
+
|
22
|
+
import { QuantityStyleSheet } from "./stylesheet/quantity.mjs";
|
23
|
+
import "./input-group.mjs";
|
24
|
+
|
25
|
+
export { Quantity };
|
26
|
+
|
27
|
+
const controlElementSymbol = Symbol("quantityControl");
|
28
|
+
const decrementButtonSymbol = Symbol("decrementButton");
|
29
|
+
const incrementButtonSymbol = Symbol("incrementButton");
|
30
|
+
const inputElementSymbol = Symbol("quantityInput");
|
31
|
+
const holdTimerSymbol = Symbol("holdTimer");
|
32
|
+
const holdIntervalSymbol = Symbol("holdInterval");
|
33
|
+
|
34
|
+
/**
|
35
|
+
* This Control shows an input field with increment and decrement buttons.
|
36
|
+
*
|
37
|
+
* @fragments /fragments/components/form/quantity/
|
38
|
+
*
|
39
|
+
* @example /examples/components/form/quantity-simple
|
40
|
+
*
|
41
|
+
* @since 4.41.0
|
42
|
+
* @copyright schukai GmbH
|
43
|
+
* @summary A beautiful quantity control with increment and decrement buttons
|
44
|
+
* @fires monster-quantity-change
|
45
|
+
*/
|
46
|
+
class Quantity extends CustomControl {
|
47
|
+
static get [instanceSymbol]() {
|
48
|
+
return Symbol.for("@schukai/monster/components/form/quantity@@instance");
|
49
|
+
}
|
50
|
+
|
51
|
+
[assembleMethodSymbol]() {
|
52
|
+
super[assembleMethodSymbol]();
|
53
|
+
|
54
|
+
initControlReferences.call(this);
|
55
|
+
initEventHandler.call(this);
|
56
|
+
applyEditableState.call(this);
|
57
|
+
clampAndRender.call(this, this.getOption("value"));
|
58
|
+
|
59
|
+
return this;
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Current numeric value
|
64
|
+
* @return {number|null}
|
65
|
+
*/
|
66
|
+
get value() {
|
67
|
+
return this.getOption("value");
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Sets the value programmatically (including clamping & FormValue)
|
72
|
+
* @param {number|string|null} v
|
73
|
+
*/
|
74
|
+
set value(v) {
|
75
|
+
const n = normalizeNumber(v, this.getOption("precision"));
|
76
|
+
clampAndRender.call(this, n);
|
77
|
+
}
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Options
|
81
|
+
*
|
82
|
+
* @property {Object} templates
|
83
|
+
* @property {string} templates.main Main template
|
84
|
+
* @property {Object} templateMapping
|
85
|
+
* @property {string} templateMapping.plus Icon (SVG-Path) Plus
|
86
|
+
* @property {string} templateMapping.minus Icon (SVG-Path) Minus
|
87
|
+
* @property {Object} classes CSS classes
|
88
|
+
* @property {string} classes.button Button class (e.g. monster-button-outline-primary)
|
89
|
+
* @property {string} classes.input Additional class for input
|
90
|
+
* @property {Object} features Feature toggles
|
91
|
+
* @property {boolean} features.editable Allow manual input
|
92
|
+
* @property {boolean} features.hold Press-and-hold accelerates
|
93
|
+
* @property {boolean} features.enforceBounds Clamp value when manual input is out of bounds
|
94
|
+
* @property {number} value Current value
|
95
|
+
* @property {number} min Use Number.NEGATIVE_INFINITY and Number.POSITIVE_INFINITY for no bounds
|
96
|
+
* @property {number} max Use Number.NEGATIVE_INFINITY and Number.POSITIVE_INFINITY for no bounds
|
97
|
+
* @property {number} step Increment/decrement step
|
98
|
+
* @property {number} precision Round to N decimal places (null = no explicit rounding)
|
99
|
+
* @property {boolean} disabled Disable the input field (also disables manual input)
|
100
|
+
* @property {string} placeholder Placeholder text
|
101
|
+
* @property {string} inputmode For mobile keyboards
|
102
|
+
*/
|
103
|
+
get defaults() {
|
104
|
+
return Object.assign({}, super.defaults, {
|
105
|
+
templates: { main: getTemplate() },
|
106
|
+
templateMapping: {
|
107
|
+
plus: `
|
108
|
+
<path d="M8 1a1 1 0 0 1 1 1v5h5a1 1 0 1 1 0 2H9v5a1 1 0 1 1-2 0V9H2a1 1 0 1 1 0-2h5V2a1 1 0 0 1 1-1z"/>`,
|
109
|
+
minus: `
|
110
|
+
<path d="M2 7.5a1 1 0 0 0 0 1H14a1 1 0 1 0 0-2H2a1 1 0 0 0 0 1z"/>`,
|
111
|
+
},
|
112
|
+
classes: {
|
113
|
+
button: "monster-button-outline-primary",
|
114
|
+
input: "",
|
115
|
+
},
|
116
|
+
features: {
|
117
|
+
editable: true,
|
118
|
+
hold: true,
|
119
|
+
enforceBounds: true,
|
120
|
+
},
|
121
|
+
value: 0,
|
122
|
+
min: 0,
|
123
|
+
max: Number.POSITIVE_INFINITY,
|
124
|
+
step: 1,
|
125
|
+
precision: null,
|
126
|
+
|
127
|
+
disabled: false,
|
128
|
+
placeholder: "",
|
129
|
+
inputmode: "decimal",
|
130
|
+
});
|
131
|
+
}
|
132
|
+
|
133
|
+
static getTag() {
|
134
|
+
return "monster-quantity";
|
135
|
+
}
|
136
|
+
|
137
|
+
// If you want a stylesheet, return it here.
|
138
|
+
static getCSSStyleSheet() {
|
139
|
+
return [QuantityStyleSheet];
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
/* -------------------------- internals ----------------------------------- */
|
144
|
+
|
145
|
+
function initControlReferences() {
|
146
|
+
this[controlElementSymbol] = this.shadowRoot.querySelector(
|
147
|
+
`[${ATTRIBUTE_ROLE}="control"]`,
|
148
|
+
);
|
149
|
+
this[decrementButtonSymbol] = this.shadowRoot.querySelector(
|
150
|
+
`[${ATTRIBUTE_ROLE}="decrement"]`,
|
151
|
+
);
|
152
|
+
this[incrementButtonSymbol] = this.shadowRoot.querySelector(
|
153
|
+
`[${ATTRIBUTE_ROLE}="increment"]`,
|
154
|
+
);
|
155
|
+
this[inputElementSymbol] = this.shadowRoot.querySelector(
|
156
|
+
`[${ATTRIBUTE_ROLE}="input"]`,
|
157
|
+
);
|
158
|
+
}
|
159
|
+
|
160
|
+
function initEventHandler() {
|
161
|
+
const stepOnce = (dir) => {
|
162
|
+
const step = Number(this.getOption("step")) || 1;
|
163
|
+
const cur = toNumberOr(this.value, 0);
|
164
|
+
const next = cur + (dir > 0 ? step : -step);
|
165
|
+
clampAndRender.call(this, next, {
|
166
|
+
fire: true,
|
167
|
+
kind: dir > 0 ? "increment" : "decrement",
|
168
|
+
});
|
169
|
+
};
|
170
|
+
|
171
|
+
const startHold = (dir) => {
|
172
|
+
if (!this.getOption("features.hold")) return;
|
173
|
+
clearTimeout(this[holdTimerSymbol]);
|
174
|
+
clearInterval(this[holdIntervalSymbol]);
|
175
|
+
|
176
|
+
// After a short delay, repeat faster
|
177
|
+
this[holdTimerSymbol] = setTimeout(() => {
|
178
|
+
this[holdIntervalSymbol] = setInterval(() => stepOnce(dir), 60);
|
179
|
+
}, 300);
|
180
|
+
};
|
181
|
+
|
182
|
+
const stopHold = () => {
|
183
|
+
clearTimeout(this[holdTimerSymbol]);
|
184
|
+
clearInterval(this[holdIntervalSymbol]);
|
185
|
+
};
|
186
|
+
|
187
|
+
// Buttons
|
188
|
+
this[decrementButtonSymbol].addEventListener("click", (e) => stepOnce(-1));
|
189
|
+
this[incrementButtonSymbol].addEventListener("click", (e) => stepOnce(1));
|
190
|
+
|
191
|
+
// Press & hold (Mouse/Touch)
|
192
|
+
["mousedown", "pointerdown", "touchstart"].forEach((ev) => {
|
193
|
+
this[decrementButtonSymbol].addEventListener(ev, () => startHold(-1));
|
194
|
+
this[incrementButtonSymbol].addEventListener(ev, () => startHold(1));
|
195
|
+
});
|
196
|
+
["mouseup", "mouseleave", "pointerup", "touchend", "touchcancel"].forEach(
|
197
|
+
(ev) => {
|
198
|
+
this[decrementButtonSymbol].addEventListener(ev, stopHold);
|
199
|
+
this[incrementButtonSymbol].addEventListener(ev, stopHold);
|
200
|
+
},
|
201
|
+
);
|
202
|
+
|
203
|
+
// Keyboard on input
|
204
|
+
this[inputElementSymbol].addEventListener("keydown", (e) => {
|
205
|
+
if (e.key === "ArrowUp") {
|
206
|
+
e.preventDefault();
|
207
|
+
stepOnce(1);
|
208
|
+
} else if (e.key === "ArrowDown") {
|
209
|
+
e.preventDefault();
|
210
|
+
stepOnce(-1);
|
211
|
+
}
|
212
|
+
});
|
213
|
+
|
214
|
+
// Manual input
|
215
|
+
this[inputElementSymbol].addEventListener("input", () => {
|
216
|
+
if (!this.getOption("features.editable")) return;
|
217
|
+
// Only store temporarily, clamp on blur/enter – but update FormValue immediately
|
218
|
+
const raw = this[inputElementSymbol].value;
|
219
|
+
const n = normalizeNumber(raw, this.getOption("precision"));
|
220
|
+
this.setOption("value", n);
|
221
|
+
this.setFormValue(n);
|
222
|
+
fireChanged.call(this, "input");
|
223
|
+
});
|
224
|
+
|
225
|
+
this[inputElementSymbol].addEventListener("blur", () => {
|
226
|
+
if (!this.getOption("features.editable")) return;
|
227
|
+
const n = normalizeNumber(
|
228
|
+
this[inputElementSymbol].value,
|
229
|
+
this.getOption("precision"),
|
230
|
+
);
|
231
|
+
clampAndRender.call(this, n, { fire: true, kind: "blur" });
|
232
|
+
});
|
233
|
+
}
|
234
|
+
|
235
|
+
function applyEditableState() {
|
236
|
+
const editable = !!this.getOption("features.editable");
|
237
|
+
this[inputElementSymbol].toggleAttribute("readonly", !editable);
|
238
|
+
this[inputElementSymbol].toggleAttribute(
|
239
|
+
"disabled",
|
240
|
+
!!this.getOption("disabled"),
|
241
|
+
);
|
242
|
+
}
|
243
|
+
|
244
|
+
function clampAndRender(n, opts = {}) {
|
245
|
+
const min = Number.isFinite(this.getOption("min"))
|
246
|
+
? Number(this.getOption("min"))
|
247
|
+
: Number.NEGATIVE_INFINITY;
|
248
|
+
const max = Number.isFinite(this.getOption("max"))
|
249
|
+
? Number(this.getOption("max"))
|
250
|
+
: Number.POSITIVE_INFINITY;
|
251
|
+
|
252
|
+
let value = n;
|
253
|
+
if (this.getOption("features.enforceBounds")) {
|
254
|
+
value = Math.min(max, Math.max(min, toNumberOr(n, 0)));
|
255
|
+
}
|
256
|
+
|
257
|
+
// Precision
|
258
|
+
const p = this.getOption("precision");
|
259
|
+
if (Number.isInteger(p) && p >= 0) {
|
260
|
+
value = Number(toFixedSafe(value, p));
|
261
|
+
}
|
262
|
+
|
263
|
+
// Render into input
|
264
|
+
this[inputElementSymbol].value =
|
265
|
+
value === null || Number.isNaN(value) ? "" : String(value);
|
266
|
+
|
267
|
+
// Options + FormValue
|
268
|
+
this.setOption("value", value);
|
269
|
+
this.setFormValue(value);
|
270
|
+
|
271
|
+
if (opts.fire) fireChanged.call(this, opts.kind || "programmatic");
|
272
|
+
}
|
273
|
+
|
274
|
+
function fireChanged(kind) {
|
275
|
+
fireCustomEvent(this, "monster-quantity-change", {
|
276
|
+
element: this,
|
277
|
+
value: this.value,
|
278
|
+
kind, // 'increment' | 'decrement' | 'input' | 'blur' | 'programmatic'
|
279
|
+
});
|
280
|
+
}
|
281
|
+
|
282
|
+
function normalizeNumber(v, precision) {
|
283
|
+
if (v === null || v === undefined || v === "") return null;
|
284
|
+
let n = Number(v);
|
285
|
+
if (!Number.isFinite(n)) return null;
|
286
|
+
if (Number.isInteger(precision) && precision >= 0) {
|
287
|
+
n = Number(toFixedSafe(n, precision));
|
288
|
+
}
|
289
|
+
return n;
|
290
|
+
}
|
291
|
+
|
292
|
+
function toNumberOr(v, dflt) {
|
293
|
+
const n = Number(v);
|
294
|
+
return Number.isFinite(n) ? n : dflt;
|
295
|
+
}
|
296
|
+
|
297
|
+
function toFixedSafe(n, p) {
|
298
|
+
// Prevents 1.00000000000002 effects
|
299
|
+
return (Math.round(n * Math.pow(10, p)) / Math.pow(10, p)).toFixed(p);
|
300
|
+
}
|
301
|
+
|
302
|
+
function getTemplate() {
|
303
|
+
// language=HTML
|
304
|
+
return `
|
305
|
+
<div data-monster-role="control" part="control">
|
306
|
+
<monster-input-group part="input-group">
|
307
|
+
<button type="button"
|
308
|
+
part="decrement-button"
|
309
|
+
data-monster-attributes="class path:classes.button"
|
310
|
+
data-monster-role="decrement"
|
311
|
+
aria-label="decrement">
|
312
|
+
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor"
|
313
|
+
>\${minus}</svg>
|
314
|
+
</button>
|
315
|
+
|
316
|
+
<input data-monster-role="input"
|
317
|
+
part="input"
|
318
|
+
class="\${classes.input}"
|
319
|
+
data-monster-attributes="
|
320
|
+
placeholder path:placeholder,
|
321
|
+
inputmode path:inputmode"
|
322
|
+
autocomplete="off" />
|
323
|
+
|
324
|
+
<button type="button"
|
325
|
+
part="increment-button"
|
326
|
+
data-monster-attributes="class path:classes.button"
|
327
|
+
data-monster-role="increment"
|
328
|
+
aria-label="increment">
|
329
|
+
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor">\${plus}</svg>
|
330
|
+
</button>
|
331
|
+
</monster-input-group>
|
332
|
+
</div>
|
333
|
+
`;
|
334
|
+
}
|
335
|
+
|
336
|
+
registerCustomElement(Quantity);
|
@@ -1938,21 +1938,19 @@ function setTotalText() {
|
|
1938
1938
|
|
1939
1939
|
const count = this.getOption("options").length;
|
1940
1940
|
const total = Number.parseInt(this.getOption("total"));
|
1941
|
-
|
1942
1941
|
if (Number.isNaN(total)) {
|
1943
1942
|
this.setOption("messages.total", "");
|
1944
1943
|
return;
|
1945
1944
|
}
|
1946
1945
|
|
1947
1946
|
const translations = getDefaultTranslation.call(this);
|
1948
|
-
const text = translations.getPluralRuleText("total", total, "");
|
1949
1947
|
|
1950
1948
|
const diff = total - count;
|
1951
1949
|
if (diff < 0) {
|
1952
1950
|
this.setOption("messages.total", "");
|
1953
1951
|
return;
|
1954
1952
|
}
|
1955
|
-
|
1953
|
+
const text = translations.getPluralRuleText("total", diff, "");
|
1956
1954
|
const selectedText = new Formatter({
|
1957
1955
|
count: String(diff),
|
1958
1956
|
}).format(text);
|
@@ -0,0 +1,150 @@
|
|
1
|
+
/* monster-quantity – Theme-aware using central Monster tokens */
|
2
|
+
|
3
|
+
:host {
|
4
|
+
/* Size tokens */
|
5
|
+
--qty-height: 40px;
|
6
|
+
--qty-radius: 0;
|
7
|
+
--qty-gap: var(--monster-space-4);
|
8
|
+
--qty-pad-x: var(--monster-space-4);
|
9
|
+
|
10
|
+
/* Anbindung an eure zentralen Tokens */
|
11
|
+
--qty-bg: var(--monster-theme-control-bg-color);
|
12
|
+
--qty-fg: var(--monster-theme-control-color);
|
13
|
+
--qty-border-color: var(--monster-theme-control-border-color);
|
14
|
+
--qty-outline: var(--monster-outline-width) solid var(--monster-theme-control-border-color);
|
15
|
+
|
16
|
+
/* Buttons */
|
17
|
+
--qty-btn-bg: var(--monster-bg-color-primary-3);
|
18
|
+
--qty-btn-bg-hover: var(--monster-bg-color-primary-4);
|
19
|
+
--qty-btn-bg-active: var(--monster-bg-color-primary-2);
|
20
|
+
--qty-btn-fg: var(--monster-color-primary-3);
|
21
|
+
|
22
|
+
/* Input */
|
23
|
+
--qty-input-fg: var(--monster-color-primary-1);
|
24
|
+
--qty-input-bg: transparent;
|
25
|
+
|
26
|
+
--qty-shadow:none;
|
27
|
+
color: var(--qty-fg);
|
28
|
+
font-family: var(--monster-font-family);
|
29
|
+
}
|
30
|
+
|
31
|
+
/* Container */
|
32
|
+
[part="control"] {
|
33
|
+
display: inline-flex;
|
34
|
+
vertical-align: middle;
|
35
|
+
}
|
36
|
+
|
37
|
+
/* Pill-Group */
|
38
|
+
[part="input-group"] {
|
39
|
+
display: inline-grid;
|
40
|
+
grid-auto-flow: column;
|
41
|
+
align-items: center;
|
42
|
+
gap: var(--qty-gap);
|
43
|
+
height: var(--qty-height);
|
44
|
+
padding-inline: var(--qty-pad-x);
|
45
|
+
background: var(--qty-bg);
|
46
|
+
color: var(--qty-fg);
|
47
|
+
border: var(--monster-theme-control-border-width, 1px)
|
48
|
+
var(--monster-theme-control-border-style, solid)
|
49
|
+
var(--qty-border-color);
|
50
|
+
border-radius: var(--qty-radius);
|
51
|
+
box-shadow: var(--qty-shadow);
|
52
|
+
}
|
53
|
+
|
54
|
+
/* Buttons */
|
55
|
+
[part="decrement-button"],
|
56
|
+
[part="increment-button"] {
|
57
|
+
display: inline-grid;
|
58
|
+
place-items: center;
|
59
|
+
width: calc(var(--qty-height) - var(--monster-space-4));
|
60
|
+
height: calc(var(--qty-height) - var(--monster-space-4));
|
61
|
+
border: 0;
|
62
|
+
border-radius: var(--qty-radius);
|
63
|
+
background: var(--qty-btn-bg);
|
64
|
+
color: var(--qty-btn-fg);
|
65
|
+
cursor: pointer;
|
66
|
+
transition: transform .08s ease, background-color .15s ease;
|
67
|
+
}
|
68
|
+
|
69
|
+
[part="decrement-button"] {
|
70
|
+
transform: translateX(-7px);
|
71
|
+
}
|
72
|
+
[part="increment-button"] {
|
73
|
+
transform: translateX(7px);
|
74
|
+
}
|
75
|
+
|
76
|
+
|
77
|
+
[part="decrement-button"]:hover,
|
78
|
+
[part="increment-button"]:hover {
|
79
|
+
background: var(--qty-btn-bg-hover);
|
80
|
+
}
|
81
|
+
|
82
|
+
[part="decrement-button"]:active,
|
83
|
+
[part="increment-button"]:active {
|
84
|
+
background: var(--qty-btn-bg-active);
|
85
|
+
}
|
86
|
+
|
87
|
+
[part="decrement-button"]:active {
|
88
|
+
transform: scale(.95) translateX(-7px);
|
89
|
+
}
|
90
|
+
[part="increment-button"]:active {
|
91
|
+
transform: scale(.95) translateX(7px);
|
92
|
+
}
|
93
|
+
|
94
|
+
[part="decrement-button"] svg,
|
95
|
+
[part="increment-button"] svg {
|
96
|
+
width: 18px;
|
97
|
+
height: 18px;
|
98
|
+
display: block;
|
99
|
+
pointer-events: none;
|
100
|
+
}
|
101
|
+
|
102
|
+
/* Input */
|
103
|
+
[part="input"] {
|
104
|
+
min-width: 2.5ch;
|
105
|
+
max-width: 6.5ch;
|
106
|
+
text-align: center;
|
107
|
+
font: inherit;
|
108
|
+
color: var(--qty-input-fg);
|
109
|
+
background: var(--qty-input-bg);
|
110
|
+
border: 0;
|
111
|
+
outline: none;
|
112
|
+
padding: 0 .25rem;
|
113
|
+
appearance: textfield; /* Safari */
|
114
|
+
}
|
115
|
+
|
116
|
+
/* Native Number-Spinner entfernen (falls type=number verwendet wird) */
|
117
|
+
[part="input"]::-webkit-outer-spin-button,
|
118
|
+
[part="input"]::-webkit-inner-spin-button {
|
119
|
+
-webkit-appearance: none;
|
120
|
+
margin: 0;
|
121
|
+
}
|
122
|
+
|
123
|
+
/* Fokus */
|
124
|
+
:host(:focus-within) [part="input-group"] {
|
125
|
+
outline: var(--qty-outline);
|
126
|
+
outline-offset: 2px;
|
127
|
+
}
|
128
|
+
|
129
|
+
/* Disabled */
|
130
|
+
:host([disabled]) [part="decrement-button"],
|
131
|
+
:host([disabled]) [part="increment-button"] {
|
132
|
+
opacity: .5;
|
133
|
+
cursor: not-allowed;
|
134
|
+
}
|
135
|
+
|
136
|
+
:host([disabled]) [part="input"] {
|
137
|
+
opacity: .75;
|
138
|
+
cursor: not-allowed;
|
139
|
+
}
|
140
|
+
|
141
|
+
/* Größen-Varianten */
|
142
|
+
:host([data-size="compact"]) { --qty-height: 32px; }
|
143
|
+
:host([data-size="large"]) { --qty-height: 48px; }
|
144
|
+
|
145
|
+
/* Motion */
|
146
|
+
@media (prefers-reduced-motion: reduce) {
|
147
|
+
[part="decrement-button"],
|
148
|
+
[part="increment-button"] { transition: none; }
|
149
|
+
}
|
150
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright © schukai GmbH and all contributing authors, 2025. 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 {addAttributeToken} from "../../../dom/attributes.mjs";
|
14
|
+
import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs";
|
15
|
+
|
16
|
+
export {QuantityStyleSheet}
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @private
|
20
|
+
* @type {CSSStyleSheet}
|
21
|
+
*/
|
22
|
+
const QuantityStyleSheet = new CSSStyleSheet();
|
23
|
+
|
24
|
+
try {
|
25
|
+
QuantityStyleSheet.insertRule(`
|
26
|
+
@layer quantity {
|
27
|
+
:host{--qty-height:40px;--qty-radius:0;--qty-gap:var(--monster-space-4);--qty-pad-x:var(--monster-space-4);--qty-bg:var(--monster-theme-control-bg-color);--qty-fg:var(--monster-theme-control-color);--qty-border-color:var(--monster-theme-control-border-color);--qty-outline:var(--monster-outline-width) solid var(--monster-theme-control-border-color);--qty-btn-bg:var(--monster-bg-color-primary-3);--qty-btn-bg-hover:var(--monster-bg-color-primary-4);--qty-btn-bg-active:var(--monster-bg-color-primary-2);--qty-btn-fg:var(--monster-color-primary-3);--qty-input-fg:var(--monster-color-primary-1);--qty-input-bg:transparent;--qty-shadow:none;color:var(--qty-fg);font-family:var(--monster-font-family)}[part=control]{display:inline-flex;vertical-align:middle}[part=input-group]{align-items:center;background:var(--qty-bg);border:var(--monster-theme-control-border-width,1px) var(--monster-theme-control-border-style,solid) var(--qty-border-color);border-radius:var(--qty-radius);box-shadow:var(--qty-shadow);color:var(--qty-fg);display:inline-grid;gap:var(--qty-gap);grid-auto-flow:column;height:var(--qty-height);padding-inline:var(--qty-pad-x)}[part=decrement-button],[part=increment-button]{background:var(--qty-btn-bg);border:0;border-radius:var(--qty-radius);color:var(--qty-btn-fg);cursor:pointer;display:inline-grid;height:calc(var(--qty-height) - var(--monster-space-4));place-items:center;transition:transform .08s ease,background-color .15s ease;width:calc(var(--qty-height) - var(--monster-space-4))}[part=decrement-button]{transform:translateX(-7px)}[part=increment-button]{transform:translateX(7px)}[part=decrement-button]:hover,[part=increment-button]:hover{background:var(--qty-btn-bg-hover)}[part=decrement-button]:active,[part=increment-button]:active{background:var(--qty-btn-bg-active)}[part=decrement-button]:active{transform:scale(.95) translateX(-7px)}[part=increment-button]:active{transform:scale(.95) translateX(7px)}[part=decrement-button] svg,[part=increment-button] svg{display:block;height:18px;pointer-events:none;width:18px}[part=input]{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:var(--qty-input-bg);border:0;color:var(--qty-input-fg);font:inherit;max-width:6.5ch;min-width:2.5ch;outline:none;padding:0 .25rem;text-align:center}[part=input]::-webkit-inner-spin-button,[part=input]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}:host(:focus-within) [part=input-group]{outline:var(--qty-outline);outline-offset:2px}:host([disabled]) [part=decrement-button],:host([disabled]) [part=increment-button]{cursor:not-allowed;opacity:.5}:host([disabled]) [part=input]{cursor:not-allowed;opacity:.75}:host([data-size=compact]){--qty-height:32px}:host([data-size=large]){--qty-height:48px}@media (prefers-reduced-motion:reduce){[part=decrement-button],[part=increment-button]{transition:none}}
|
28
|
+
}`, 0);
|
29
|
+
} catch (e) {
|
30
|
+
addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + "");
|
31
|
+
}
|