-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathNumber.ts
More file actions
131 lines (113 loc) · 2.98 KB
/
Number.ts
File metadata and controls
131 lines (113 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { ref } from "lit/directives/ref.js";
import { LocalizedMessage, localizedMessagePropertyOptions } from "../core/";
import { Focusable, Input, Persisted } from "../mixins";
@customElement("sdpi-number")
export class NumberElement extends Persisted(Focusable(Input<typeof LitElement, number>(LitElement))) {
/** @inheritdoc */
public static get styles() {
return [
...super.styles,
css`
input {
background-color: var(--input-bg-color);
padding: calc(var(--spacer) + 3px) var(--spacer);
flex: 1;
min-width: unset;
max-width: unset;
}
::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input:disabled {
opacity: var(--opacity-disabled);
}
.number-container {
display: flex;
width: 100%;
}
`
];
}
/**
* The maximum value.
*/
@property({ type: Number })
public max?: number;
/**
* The minimum value.
*/
@property({ type: Number })
public min?: number;
/**
* Specifies the granularity that the value must adhere to.
*/
@property({ type: Number })
public step?: number;
/**
* Specifies the placeholder
*/
@property(localizedMessagePropertyOptions)
public placeholder?: LocalizedMessage;
/**
* When specified, the user input will be clamped to the maximum and maximum values provided
*/
@property({
attribute: "clamp",
type: Boolean,
})
public clamp = false;
/** @inheritdoc */
protected delaySave = true;
/** @inheritdoc */
protected render() {
const value = this.value?.toString() || this.defaultValue?.toString() || "";
return html`
<label class="number-container">
<input
${ref(this.focusElement)}
type="number"
max=${ifDefined(this.max)}
min=${ifDefined(this.min)}
step=${ifDefined(this.step)}
placeholder=${ifDefined(this.placeholder)}
.disabled=${this.disabled}
.value=${value}
@change=${(ev: HTMLInputEvent<HTMLInputElement>) => (this.setValue(ev))}
/>
<slot name="suffix"></slot>
</label>`;
}
private setValue(ev: HTMLInputEvent<HTMLInputElement>): void {
let value = ev.target.valueAsNumber;
if (Number.isNaN(value)) {
// No value provided
this.value = undefined;
return
}
// Constrain value to min and max if provided
const min = this.clamp ? this.min : undefined;
const max = this.clamp ? this.max : undefined;
if (max != undefined) {
value = Math.min(value, max);
}
if (min != undefined) {
value = Math.max(value, min);
}
// Force step size
if (this.step != undefined) {
// This matches the native step size on the number type input
const stepStart = this.min ?? 0.0;
value = Math.round((value - stepStart) / this.step) * this.step + stepStart;
}
this.value = value;
ev.target.value = String(this.value);
}
}
declare global {
interface HTMLElementTagNameMap {
"sdpi-number": NumberElement;
}
}