@openremote/or-mwc-components 1.8.0 → 1.8.1
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/package.json +7 -7
- package/build.gradle +0 -36
- package/playwright.config.ts +0 -3
- package/rspack.config.js +0 -7
- package/src/or-mwc-dialog.ts +0 -374
- package/src/or-mwc-drawer.ts +0 -100
- package/src/or-mwc-input.ts +0 -1876
- package/src/or-mwc-list.ts +0 -335
- package/src/or-mwc-menu.ts +0 -279
- package/src/or-mwc-snackbar.ts +0 -157
- package/src/or-mwc-table.ts +0 -712
- package/src/or-mwc-tabs.ts +0 -175
- package/src/style.ts +0 -125
- package/test/or-mwc-input.test.ts +0 -46
- package/tsconfig.json +0 -15
- package/tsconfig.tsbuildinfo +0 -1
package/src/or-mwc-input.ts
DELETED
|
@@ -1,1876 +0,0 @@
|
|
|
1
|
-
import {css, html, LitElement, PropertyValues, TemplateResult, unsafeCSS} from "lit";
|
|
2
|
-
import {customElement, property, state} from "lit/decorators.js";
|
|
3
|
-
import {Ref, ref, createRef} from "lit/directives/ref.js";
|
|
4
|
-
import {classMap} from "lit/directives/class-map.js";
|
|
5
|
-
import {ifDefined} from "lit/directives/if-defined.js";
|
|
6
|
-
import {when} from 'lit/directives/when.js';
|
|
7
|
-
import {until} from 'lit/directives/until.js';
|
|
8
|
-
import {MDCTextField} from "@material/textfield";
|
|
9
|
-
import {MDCComponent} from "@material/base";
|
|
10
|
-
import {MDCRipple} from "@material/ripple";
|
|
11
|
-
import {MDCCheckbox} from "@material/checkbox";
|
|
12
|
-
import {MDCSwitch} from "@material/switch";
|
|
13
|
-
import {MDCSlider, MDCSliderChangeEventDetail} from "@material/slider";
|
|
14
|
-
import {MDCSelect, MDCSelectEvent} from "@material/select";
|
|
15
|
-
import {MDCList, MDCListActionEvent} from "@material/list";
|
|
16
|
-
|
|
17
|
-
import {MDCFormField, MDCFormFieldInput} from "@material/form-field";
|
|
18
|
-
import {MDCIconButtonToggle, MDCIconButtonToggleEventDetail} from "@material/icon-button";
|
|
19
|
-
import {DefaultColor4, DefaultColor5, DefaultColor8, Util} from "@openremote/core";
|
|
20
|
-
import "@openremote/or-icon";
|
|
21
|
-
import {OrIcon} from "@openremote/or-icon";
|
|
22
|
-
import {
|
|
23
|
-
AssetDescriptor,
|
|
24
|
-
Attribute,
|
|
25
|
-
AttributeDescriptor,
|
|
26
|
-
MetaHolder,
|
|
27
|
-
NameHolder,
|
|
28
|
-
NameValueHolder,
|
|
29
|
-
ValueConstraint,
|
|
30
|
-
ValueConstraintAllowedValues,
|
|
31
|
-
ValueConstraintFuture,
|
|
32
|
-
ValueConstraintFutureOrPresent,
|
|
33
|
-
ValueConstraintMax,
|
|
34
|
-
ValueConstraintMin,
|
|
35
|
-
ValueConstraintNotBlank,
|
|
36
|
-
ValueConstraintNotEmpty,
|
|
37
|
-
ValueConstraintNotNull,
|
|
38
|
-
ValueConstraintPast,
|
|
39
|
-
ValueConstraintPastOrPresent,
|
|
40
|
-
ValueConstraintPattern,
|
|
41
|
-
ValueConstraintSize,
|
|
42
|
-
ValueDescriptor,
|
|
43
|
-
ValueDescriptorHolder,
|
|
44
|
-
ValueFormat,
|
|
45
|
-
ValueFormatStyleRepresentation,
|
|
46
|
-
ValueHolder,
|
|
47
|
-
WellknownMetaItems,
|
|
48
|
-
WellknownValueTypes
|
|
49
|
-
} from "@openremote/model";
|
|
50
|
-
import {getItemTemplate, getListTemplate, ListItem, ListType} from "./or-mwc-list";
|
|
51
|
-
import { i18next } from "@openremote/or-translate";
|
|
52
|
-
import { styleMap } from "lit/directives/style-map.js";
|
|
53
|
-
|
|
54
|
-
// TODO: Add webpack/rollup to build so consumers aren't forced to use the same tooling
|
|
55
|
-
const buttonStyle = require("@material/button/dist/mdc.button.css");
|
|
56
|
-
const buttonFabStyle = require("@material/fab/dist/mdc.fab.css");
|
|
57
|
-
const iconButtonStyle = require("@material/icon-button/dist/mdc.icon-button.css");
|
|
58
|
-
const textfieldStyle = require("@material/textfield/dist/mdc.textfield.css");
|
|
59
|
-
const rippleStyle = require("@material/ripple/dist/mdc.ripple.css");
|
|
60
|
-
const lineRippleStyle = require("@material/line-ripple/dist/mdc.line-ripple.css");
|
|
61
|
-
const floatingLabelStyle = require("@material/floating-label/dist/mdc.floating-label.css");
|
|
62
|
-
const formFieldStyle = require("@material/form-field/dist/mdc.form-field.css");
|
|
63
|
-
const checkboxStyle = require("@material/checkbox/dist/mdc.checkbox.css");
|
|
64
|
-
const radioStyle = require("@material/radio/dist/mdc.radio.css");
|
|
65
|
-
const switchStyle = require("@material/switch/dist/mdc.switch.css");
|
|
66
|
-
const selectStyle = require("@material/select/dist/mdc.select.css");
|
|
67
|
-
const listStyle = require("@material/list/dist/mdc.list.css");
|
|
68
|
-
const menuSurfaceStyle = require("@material/menu-surface/dist/mdc.menu-surface.css");
|
|
69
|
-
const menuStyle = require("@material/menu/dist/mdc.menu.css");
|
|
70
|
-
const sliderStyle = require("@material/slider/dist/mdc.slider.css");
|
|
71
|
-
|
|
72
|
-
export class OrInputChangedEvent extends CustomEvent<OrInputChangedEventDetail> {
|
|
73
|
-
|
|
74
|
-
public static readonly NAME = "or-mwc-input-changed";
|
|
75
|
-
|
|
76
|
-
constructor(value?: any, previousValue?: any, enterPressed?: boolean) {
|
|
77
|
-
super(OrInputChangedEvent.NAME, {
|
|
78
|
-
detail: {
|
|
79
|
-
value: value,
|
|
80
|
-
previousValue: previousValue,
|
|
81
|
-
enterPressed: enterPressed
|
|
82
|
-
},
|
|
83
|
-
bubbles: true,
|
|
84
|
-
composed: true
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export interface OrInputChangedEventDetail {
|
|
90
|
-
value?: any;
|
|
91
|
-
previousValue?: any;
|
|
92
|
-
enterPressed?: boolean;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
declare global {
|
|
96
|
-
export interface HTMLElementEventMap {
|
|
97
|
-
[OrInputChangedEvent.NAME]: OrInputChangedEvent;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export enum InputType {
|
|
102
|
-
BUTTON = "button",
|
|
103
|
-
BUTTON_TOGGLE = "button-toggle",
|
|
104
|
-
BUTTON_MOMENTARY = "button-momentary",
|
|
105
|
-
CHECKBOX = "checkbox",
|
|
106
|
-
CHECKBOX_LIST = "checkbox-list",
|
|
107
|
-
COLOUR = "color",
|
|
108
|
-
DATE = "date",
|
|
109
|
-
DATETIME = "datetime-local",
|
|
110
|
-
EMAIL = "email",
|
|
111
|
-
JSON = "json",
|
|
112
|
-
JSON_OBJECT = "json-object",
|
|
113
|
-
MONTH = "month",
|
|
114
|
-
NUMBER = "number",
|
|
115
|
-
BIG_INT = "big-int",
|
|
116
|
-
PASSWORD = "password",
|
|
117
|
-
RADIO = "radio",
|
|
118
|
-
SWITCH = "switch",
|
|
119
|
-
RANGE = "range",
|
|
120
|
-
TELEPHONE = "tel",
|
|
121
|
-
TEXT = "text",
|
|
122
|
-
TEXTAREA = "textarea",
|
|
123
|
-
TIME = "time",
|
|
124
|
-
URL = "url",
|
|
125
|
-
WEEK = "week",
|
|
126
|
-
SELECT = "select",
|
|
127
|
-
LIST = "list",
|
|
128
|
-
CRON = "cron",
|
|
129
|
-
DURATION = "duration",
|
|
130
|
-
DURATION_TIME = "duration-time",
|
|
131
|
-
DURATION_PERIOD = "duration-period"
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface ValueInputProviderOptions {
|
|
135
|
-
label?: string;
|
|
136
|
-
required?: boolean;
|
|
137
|
-
readonly?: boolean;
|
|
138
|
-
disabled?: boolean;
|
|
139
|
-
compact?: boolean;
|
|
140
|
-
rounded?: boolean;
|
|
141
|
-
outlined?: boolean;
|
|
142
|
-
comfortable?: boolean;
|
|
143
|
-
resizeVertical?: boolean;
|
|
144
|
-
inputType?: InputType;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export interface ValueInputProvider {
|
|
148
|
-
templateFunction: ValueInputTemplateFunction;
|
|
149
|
-
supportsHelperText: boolean;
|
|
150
|
-
supportsLabel: boolean;
|
|
151
|
-
supportsSendButton: boolean;
|
|
152
|
-
validator?: () => boolean;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export type ValueInputTemplateFunction = ((value: any, focused: boolean, loading: boolean, sending: boolean, error: boolean, helperText: string | undefined) => TemplateResult | PromiseLike<TemplateResult>) | undefined;
|
|
156
|
-
|
|
157
|
-
export type ValueInputProviderGenerator = (assetDescriptor: AssetDescriptor | string, valueHolder: NameHolder & ValueHolder<any> | undefined, valueHolderDescriptor: ValueDescriptorHolder | undefined, valueDescriptor: ValueDescriptor, valueChangeNotifier: (value: OrInputChangedEventDetail | undefined) => void, options: ValueInputProviderOptions) => ValueInputProvider;
|
|
158
|
-
|
|
159
|
-
function inputTypeSupportsButton(inputType: InputType): boolean {
|
|
160
|
-
return inputType === InputType.NUMBER
|
|
161
|
-
|| inputType === InputType.BIG_INT
|
|
162
|
-
|| inputType === InputType.TELEPHONE
|
|
163
|
-
|| inputType === InputType.TEXT
|
|
164
|
-
|| inputType === InputType.PASSWORD
|
|
165
|
-
|| inputType === InputType.DATE
|
|
166
|
-
|| inputType === InputType.DATETIME
|
|
167
|
-
|| inputType === InputType.EMAIL
|
|
168
|
-
|| inputType === InputType.JSON
|
|
169
|
-
|| inputType === InputType.JSON_OBJECT
|
|
170
|
-
|| inputType === InputType.MONTH
|
|
171
|
-
|| inputType === InputType.TEXTAREA
|
|
172
|
-
|| inputType === InputType.TIME
|
|
173
|
-
|| inputType === InputType.URL
|
|
174
|
-
|| inputType === InputType.WEEK;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function inputTypeSupportsHelperText(inputType: InputType) {
|
|
178
|
-
return inputTypeSupportsButton(inputType) || inputType === InputType.SELECT;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function inputTypeSupportsLabel(inputType: InputType) {
|
|
182
|
-
return inputTypeSupportsHelperText(inputType) || inputType === InputType.CHECKBOX || inputType === InputType.BUTTON_MOMENTARY;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export const getValueHolderInputTemplateProvider: ValueInputProviderGenerator = (assetDescriptor, valueHolder, valueHolderDescriptor, valueDescriptor, valueChangeNotifier, options) => {
|
|
186
|
-
|
|
187
|
-
let inputType: InputType | undefined = options.inputType;
|
|
188
|
-
let step: number | undefined;
|
|
189
|
-
let pattern: string | undefined;
|
|
190
|
-
let min: any;
|
|
191
|
-
let max: any;
|
|
192
|
-
let multiple: any;
|
|
193
|
-
let required: boolean | undefined;
|
|
194
|
-
let selectOptions: [string, string][] | undefined;
|
|
195
|
-
let valueConverter: (v: any) => any | undefined;
|
|
196
|
-
const styles = {} as any;
|
|
197
|
-
|
|
198
|
-
const assetType = typeof assetDescriptor === "string" ? assetDescriptor : assetDescriptor.name;
|
|
199
|
-
const constraints: ValueConstraint[] = (valueHolder && ((valueHolder as MetaHolder).meta) || (valueDescriptor && (valueDescriptor as MetaHolder).meta) ? Util.getAttributeValueConstraints(valueHolder as Attribute<any>, valueHolderDescriptor as AttributeDescriptor, assetType) : Util.getMetaValueConstraints(valueHolder as NameValueHolder<any>, valueHolderDescriptor as AttributeDescriptor, assetType)) || [];
|
|
200
|
-
const format: ValueFormat | undefined = (valueHolder && ((valueHolder as MetaHolder).meta) || (valueDescriptor && (valueDescriptor as MetaHolder).meta) ? Util.getAttributeValueFormat(valueHolder as Attribute<any>, valueHolderDescriptor as AttributeDescriptor, assetType) : Util.getMetaValueFormat(valueHolder as Attribute<any>, valueHolderDescriptor as AttributeDescriptor, assetType));
|
|
201
|
-
|
|
202
|
-
// Determine input type
|
|
203
|
-
if (!inputType) {
|
|
204
|
-
switch (valueDescriptor.name) {
|
|
205
|
-
case WellknownValueTypes.TEXT:
|
|
206
|
-
case WellknownValueTypes.EMAIL:
|
|
207
|
-
case WellknownValueTypes.UUID:
|
|
208
|
-
case WellknownValueTypes.ASSETID:
|
|
209
|
-
case WellknownValueTypes.HOSTORIPADDRESS:
|
|
210
|
-
case WellknownValueTypes.IPADDRESS:
|
|
211
|
-
inputType = Util.getMetaValue(WellknownMetaItems.MULTILINE, valueHolder, valueHolderDescriptor) === true ? InputType.TEXTAREA : InputType.TEXT;
|
|
212
|
-
break;
|
|
213
|
-
case WellknownValueTypes.BOOLEAN:
|
|
214
|
-
if (format && format.asNumber) {
|
|
215
|
-
inputType = InputType.NUMBER;
|
|
216
|
-
step = 1;
|
|
217
|
-
min = 0;
|
|
218
|
-
max = 1;
|
|
219
|
-
valueConverter = (v) => !!v;
|
|
220
|
-
break;
|
|
221
|
-
}
|
|
222
|
-
if (format && (format.asOnOff || format.asOpenClosed)) {
|
|
223
|
-
inputType = InputType.SWITCH;
|
|
224
|
-
} else {
|
|
225
|
-
inputType = InputType.CHECKBOX;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (format && format.asMomentary || (Util.getMetaValue(WellknownMetaItems.MOMENTARY, valueHolder, valueHolderDescriptor) === true) ) {
|
|
229
|
-
inputType = InputType.BUTTON_MOMENTARY;
|
|
230
|
-
}
|
|
231
|
-
break;
|
|
232
|
-
case WellknownValueTypes.BIGNUMBER:
|
|
233
|
-
case WellknownValueTypes.NUMBER:
|
|
234
|
-
case WellknownValueTypes.POSITIVEINTEGER:
|
|
235
|
-
case WellknownValueTypes.POSITIVENUMBER:
|
|
236
|
-
case WellknownValueTypes.LONG:
|
|
237
|
-
case WellknownValueTypes.INTEGER:
|
|
238
|
-
case WellknownValueTypes.BYTE:
|
|
239
|
-
case WellknownValueTypes.INTEGERBYTE:
|
|
240
|
-
case WellknownValueTypes.DIRECTION:
|
|
241
|
-
case WellknownValueTypes.TCPIPPORTNUMBER:
|
|
242
|
-
if (valueDescriptor.name === WellknownValueTypes.BYTE || valueDescriptor.name === WellknownValueTypes.INTEGERBYTE) {
|
|
243
|
-
min = 0;
|
|
244
|
-
max = 255;
|
|
245
|
-
step = 1;
|
|
246
|
-
} else if (valueDescriptor.name === WellknownValueTypes.INTEGER || valueDescriptor.name === WellknownValueTypes.LONG) {
|
|
247
|
-
step = 1;
|
|
248
|
-
}
|
|
249
|
-
if (format && format.asDate) {
|
|
250
|
-
inputType = InputType.DATETIME;
|
|
251
|
-
} else if (format && format.asBoolean) {
|
|
252
|
-
inputType = InputType.CHECKBOX;
|
|
253
|
-
valueConverter = (v) => v ? 1 : 0;
|
|
254
|
-
} else if (format && format.asSlider) {
|
|
255
|
-
inputType = InputType.RANGE;
|
|
256
|
-
} else {
|
|
257
|
-
inputType = InputType.NUMBER;
|
|
258
|
-
}
|
|
259
|
-
break;
|
|
260
|
-
case WellknownValueTypes.BIGINTEGER:
|
|
261
|
-
inputType = InputType.BIG_INT;
|
|
262
|
-
step = 1;
|
|
263
|
-
break;
|
|
264
|
-
case WellknownValueTypes.COLOURRGB:
|
|
265
|
-
inputType = InputType.COLOUR;
|
|
266
|
-
break;
|
|
267
|
-
case WellknownValueTypes.DATEANDTIME:
|
|
268
|
-
case WellknownValueTypes.TIMESTAMP:
|
|
269
|
-
case WellknownValueTypes.TIMESTAMPISO8601:
|
|
270
|
-
inputType = InputType.DATETIME;
|
|
271
|
-
break;
|
|
272
|
-
case WellknownValueTypes.CRONEXPRESSION:
|
|
273
|
-
inputType = InputType.CRON;
|
|
274
|
-
break;
|
|
275
|
-
case WellknownValueTypes.TIMEDURATIONISO8601:
|
|
276
|
-
inputType = InputType.DURATION_TIME;
|
|
277
|
-
break;
|
|
278
|
-
case WellknownValueTypes.PERIODDURATIONISO8601:
|
|
279
|
-
inputType = InputType.DURATION_PERIOD;
|
|
280
|
-
break;
|
|
281
|
-
case WellknownValueTypes.TIMEANDPERIODDURATIONISO8601:
|
|
282
|
-
inputType = InputType.DURATION;
|
|
283
|
-
break;
|
|
284
|
-
case WellknownValueTypes.JSONOBJECT:
|
|
285
|
-
inputType = InputType.JSON_OBJECT;
|
|
286
|
-
break;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (valueDescriptor.arrayDimensions && valueDescriptor.arrayDimensions > 0) {
|
|
290
|
-
inputType = InputType.JSON;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (!inputType) {
|
|
295
|
-
switch (valueDescriptor.jsonType) {
|
|
296
|
-
case "number":
|
|
297
|
-
case "bigint":
|
|
298
|
-
inputType = InputType.NUMBER;
|
|
299
|
-
break;
|
|
300
|
-
case "boolean":
|
|
301
|
-
inputType = InputType.CHECKBOX;
|
|
302
|
-
break;
|
|
303
|
-
case "string":
|
|
304
|
-
inputType = InputType.TEXT;
|
|
305
|
-
break;
|
|
306
|
-
case "date":
|
|
307
|
-
inputType = InputType.DATETIME;
|
|
308
|
-
break;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (!inputType) {
|
|
313
|
-
inputType = InputType.JSON;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Apply any constraints
|
|
317
|
-
const sizeConstraint = constraints && constraints.find(c => c.type === "size") as ValueConstraintSize;
|
|
318
|
-
const patternConstraint = constraints && constraints.find(c => c.type === "pattern") as ValueConstraintPattern;
|
|
319
|
-
const minConstraint = constraints && constraints.find(c => c.type === "min") as ValueConstraintMin;
|
|
320
|
-
const maxConstraint = constraints && constraints.find(c => c.type === "max") as ValueConstraintMax;
|
|
321
|
-
const allowedValuesConstraint = constraints && constraints.find(c => c.type === "allowedValues") as ValueConstraintAllowedValues;
|
|
322
|
-
const pastConstraint = constraints && constraints.find(c => c.type === "past") as ValueConstraintPast;
|
|
323
|
-
const pastOrPresentConstraint = constraints && constraints.find(c => c.type === "pastOrPresent") as ValueConstraintPastOrPresent;
|
|
324
|
-
const futureConstraint = constraints && constraints.find(c => c.type === "future") as ValueConstraintFuture;
|
|
325
|
-
const futureOrPresentConstraint = constraints && constraints.find(c => c.type === "futureOrPresent") as ValueConstraintFutureOrPresent;
|
|
326
|
-
const notEmptyConstraint = constraints && constraints.find(c => c.type === "notEmpty") as ValueConstraintNotEmpty;
|
|
327
|
-
const notBlankConstraint = constraints && constraints.find(c => c.type === "notBlank") as ValueConstraintNotBlank;
|
|
328
|
-
const notNullConstraint = constraints && constraints.find(c => c.type === "notNull") as ValueConstraintNotNull;
|
|
329
|
-
|
|
330
|
-
if (sizeConstraint) {
|
|
331
|
-
min = sizeConstraint.min;
|
|
332
|
-
max = sizeConstraint.max;
|
|
333
|
-
}
|
|
334
|
-
if (sizeConstraint) {
|
|
335
|
-
min = sizeConstraint.min;
|
|
336
|
-
max = sizeConstraint.max;
|
|
337
|
-
}
|
|
338
|
-
if (minConstraint) {
|
|
339
|
-
min = minConstraint.min;
|
|
340
|
-
}
|
|
341
|
-
if (maxConstraint) {
|
|
342
|
-
max = maxConstraint.max;
|
|
343
|
-
}
|
|
344
|
-
if (patternConstraint) {
|
|
345
|
-
pattern = patternConstraint.regexp;
|
|
346
|
-
}
|
|
347
|
-
if (notNullConstraint) {
|
|
348
|
-
required = true;
|
|
349
|
-
}
|
|
350
|
-
if (notBlankConstraint && !pattern) {
|
|
351
|
-
pattern = "\\S+";
|
|
352
|
-
} else if (notEmptyConstraint && !pattern) {
|
|
353
|
-
pattern = ".+";
|
|
354
|
-
}
|
|
355
|
-
if (allowedValuesConstraint && allowedValuesConstraint.allowedValues) {
|
|
356
|
-
const allowedLabels = allowedValuesConstraint.allowedValueNames && allowedValuesConstraint.allowedValueNames.length === allowedValuesConstraint.allowedValues.length ? allowedValuesConstraint.allowedValueNames : undefined;
|
|
357
|
-
selectOptions = allowedValuesConstraint.allowedValues.map((v, i) => {
|
|
358
|
-
let label = allowedLabels ? allowedLabels[i] : "" + v;
|
|
359
|
-
label = Util.getAllowedValueLabel(label)!;
|
|
360
|
-
return [v, label || "" + v];
|
|
361
|
-
});
|
|
362
|
-
inputType = InputType.SELECT;
|
|
363
|
-
|
|
364
|
-
if (valueDescriptor.arrayDimensions && valueDescriptor.arrayDimensions > 0) {
|
|
365
|
-
multiple = true;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (inputType === InputType.DATETIME) {
|
|
370
|
-
if (pastConstraint || pastOrPresentConstraint) {
|
|
371
|
-
min = undefined;
|
|
372
|
-
max = new Date();
|
|
373
|
-
} else if (futureConstraint || futureOrPresentConstraint) {
|
|
374
|
-
min = new Date();
|
|
375
|
-
max = undefined;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Refine the input type based on formatting
|
|
379
|
-
if (format) {
|
|
380
|
-
if (format.timeStyle && !format.dateStyle) {
|
|
381
|
-
inputType = InputType.TIME;
|
|
382
|
-
} else if (format.dateStyle && !format.timeStyle) {
|
|
383
|
-
inputType = InputType.DATE;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (inputType === InputType.NUMBER && format && format.resolution) {
|
|
389
|
-
step = format.resolution;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
if (inputType === InputType.COLOUR) {
|
|
393
|
-
styles.marginLeft = "24px"
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const supportsHelperText = inputTypeSupportsHelperText(inputType);
|
|
397
|
-
const supportsLabel = inputTypeSupportsLabel(inputType);
|
|
398
|
-
const supportsSendButton = inputTypeSupportsButton(inputType);
|
|
399
|
-
const readonly = options.readonly;
|
|
400
|
-
required = required || options.required;
|
|
401
|
-
const comfortable = options.comfortable;
|
|
402
|
-
const resizeVertical = options.resizeVertical;
|
|
403
|
-
const inputRef: Ref<OrMwcInput> = createRef();
|
|
404
|
-
|
|
405
|
-
const templateFunction: ValueInputTemplateFunction = (value, focused, loading, sending, error, helperText) => {
|
|
406
|
-
|
|
407
|
-
const disabled = options.disabled || loading || sending;
|
|
408
|
-
const label = supportsLabel ? options.label : undefined;
|
|
409
|
-
|
|
410
|
-
return html`<or-mwc-input ${ref(inputRef)} id="input" style="${styleMap(styles)}" .type="${inputType}" .label="${label}" .value="${value}" .pattern="${pattern}"
|
|
411
|
-
.min="${min}" .max="${max}" .format="${format}" .focused="${focused}" .required="${required}" .multiple="${multiple}"
|
|
412
|
-
.options="${selectOptions}" .comfortable="${comfortable}" .readonly="${readonly}" .disabled="${disabled}" .step="${step}"
|
|
413
|
-
.helperText="${helperText}" .helperPersistent="${true}" .resizeVertical="${resizeVertical}"
|
|
414
|
-
.rounded="${options.rounded}"
|
|
415
|
-
.outlined="${options.outlined}"
|
|
416
|
-
@or-mwc-input-changed="${(e: OrInputChangedEvent) => {
|
|
417
|
-
e.stopPropagation();
|
|
418
|
-
e.detail.value = valueConverter ? valueConverter(e.detail.value) : e.detail.value;
|
|
419
|
-
valueChangeNotifier(e.detail);
|
|
420
|
-
}}"></or-mwc-input>`
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
return {
|
|
424
|
-
templateFunction: templateFunction,
|
|
425
|
-
supportsHelperText: supportsHelperText,
|
|
426
|
-
supportsSendButton: supportsSendButton,
|
|
427
|
-
supportsLabel: supportsLabel,
|
|
428
|
-
validator: () => {
|
|
429
|
-
if (!inputRef.value) {
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
|
-
return inputRef.value.checkValidity();
|
|
433
|
-
}
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// language=CSS
|
|
438
|
-
const style = css`
|
|
439
|
-
|
|
440
|
-
:host {
|
|
441
|
-
display: inline-block;
|
|
442
|
-
--internal-or-mwc-input-color: var(--or-mwc-input-color, var(--or-app-color4, ${unsafeCSS(DefaultColor4)}));
|
|
443
|
-
--internal-or-mwc-input-text-color: var(--or-mwc-input-text-color, var(--or-app-color8, ${unsafeCSS(DefaultColor8)}));
|
|
444
|
-
|
|
445
|
-
--mdc-theme-primary: var(--internal-or-mwc-input-color);
|
|
446
|
-
--mdc-theme-on-primary: var(--internal-or-mwc-input-text-color);
|
|
447
|
-
--mdc-theme-secondary: var(--internal-or-mwc-input-color);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
:host([hidden]) {
|
|
451
|
-
display: none;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
:host([type=select]) {
|
|
455
|
-
height: 56px;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
#wrapper {
|
|
459
|
-
display: flex;
|
|
460
|
-
align-items: center;
|
|
461
|
-
min-height: 48px;
|
|
462
|
-
height: 100%;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
#wrapper > label {
|
|
466
|
-
white-space: nowrap;
|
|
467
|
-
margin-right: 20px;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
#component {
|
|
471
|
-
max-width: 100%;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
.mdc-text-field {
|
|
475
|
-
flex: 1 1 0;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
.mdc-list {
|
|
479
|
-
flex: 1;
|
|
480
|
-
overflow: auto;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
.mdc-select__anchor {
|
|
484
|
-
max-width: 100%;
|
|
485
|
-
width: 100%;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
.mdc-checkbox-list input {
|
|
489
|
-
display: none;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
.mdc-checkbox-list label {
|
|
493
|
-
display: block;
|
|
494
|
-
border-radius: 50%;
|
|
495
|
-
text-align: center;
|
|
496
|
-
width: 32px;
|
|
497
|
-
line-height: 32px;
|
|
498
|
-
height: 32px;
|
|
499
|
-
cursor: pointer;
|
|
500
|
-
background-color: var(--or-app-color2);
|
|
501
|
-
font-size: 13px;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
input::-webkit-calendar-picker-indicator {
|
|
505
|
-
margin: 0;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
.mdc-checkbox-list .mdc-checkbox {
|
|
509
|
-
padding: 0;
|
|
510
|
-
height: 32px;
|
|
511
|
-
width: 32px;
|
|
512
|
-
}
|
|
513
|
-
.mdc-radio-container {
|
|
514
|
-
display: flex;
|
|
515
|
-
flex-direction: column;
|
|
516
|
-
}
|
|
517
|
-
.mdc-text-field.mdc-text-field--invalid:not(.mdc-text-field--disabled) + .mdc-text-field-helper-line .mdc-text-field-helper-text {
|
|
518
|
-
color: var(--mdc-theme-error, #b00020)
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
.mdc-checkbox-list input:checked + label {
|
|
522
|
-
color: var(--or-app-color2);
|
|
523
|
-
background-color: var(--mdc-theme-primary);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
.mdc-button--rounded,
|
|
527
|
-
.or-mwc-input--rounded {
|
|
528
|
-
border-radius: 24px !important;
|
|
529
|
-
--mdc-shape-small: 32px;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
#select-searchable {
|
|
533
|
-
background-color: transparent;
|
|
534
|
-
border: 1px solid var(--or-app-color5, ${unsafeCSS(DefaultColor5)});
|
|
535
|
-
margin: 8px;
|
|
536
|
-
width: calc(100% - 16px);
|
|
537
|
-
border-radius: 4px;
|
|
538
|
-
padding: 4px 16px;
|
|
539
|
-
flex: 0 0 auto;
|
|
540
|
-
align-items: center;
|
|
541
|
-
height: auto;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
.mdc-text-field__input::-webkit-calendar-picker-indicator {
|
|
545
|
-
display: block;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
::-webkit-clear-button {display: none;}
|
|
549
|
-
::-webkit-inner-spin-button { display: none; }
|
|
550
|
-
::-webkit-datetime-edit { padding: 0em; }
|
|
551
|
-
::-webkit-datetime-edit-text { padding: 0; }
|
|
552
|
-
|
|
553
|
-
.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label {
|
|
554
|
-
color: var(--mdc-theme-primary);
|
|
555
|
-
}
|
|
556
|
-
.mdc-text-field--focused .mdc-text-field__input:required ~ .mdc-floating-label::after,
|
|
557
|
-
.mdc-text-field--focused .mdc-text-field__input:required ~ .mdc-notched-outline .mdc-floating-label::after {
|
|
558
|
-
color: var(--mdc-theme-primary);
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
.mdc-text-field__input.resize-vertical {
|
|
562
|
-
resize: vertical;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
.mdc-text-field, .mdc-text-field-helper-line {
|
|
566
|
-
width: 100%;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
.mdc-text-field.dense-comfortable, .mdc-select.dense-comfortable {
|
|
570
|
-
height: 48px;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
.mdc-text-field.dense-compact {
|
|
574
|
-
height: 36px;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
.mdc-select:not(.mdc-list) {
|
|
578
|
-
white-space: nowrap;
|
|
579
|
-
display: flex;
|
|
580
|
-
flex-direction: column;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
.mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label {
|
|
584
|
-
color: var(--mdc-theme-primary);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
.mdc-select-helper-text {
|
|
588
|
-
white-space: normal;
|
|
589
|
-
color: rgba(0, 0, 0, 0.6);
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
.mdc-icon-button {
|
|
593
|
-
padding: 0;
|
|
594
|
-
color: var(--internal-or-mwc-input-color);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
/* Give slider min width like select etc. */
|
|
598
|
-
.mdc-slider {
|
|
599
|
-
min-width: 200px;
|
|
600
|
-
flex: 1;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
.mdc-switch {
|
|
604
|
-
margin: 0 24px;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
.mdc-switch--full-width {
|
|
608
|
-
margin-left: auto;
|
|
609
|
-
}
|
|
610
|
-
.mdc-button--fullwidth {
|
|
611
|
-
width: 100%;
|
|
612
|
-
}
|
|
613
|
-
#field {
|
|
614
|
-
height: 100%;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
.mdc-select__menu .mdc-list .mdc-list-item.mdc-list-item--selected or-icon {
|
|
618
|
-
--or-icon-fill: var(--or-app-color4);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
.mdc-menu__searchable {
|
|
622
|
-
overflow: hidden;
|
|
623
|
-
}
|
|
624
|
-
.mdc-menu__searchable.mdc-menu-surface--open {
|
|
625
|
-
display: flex;
|
|
626
|
-
flex-direction: column-reverse;
|
|
627
|
-
}
|
|
628
|
-
.mdc-menu__searchable.mdc-menu-surface--is-open-below {
|
|
629
|
-
flex-direction: column;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
/* Prevent mouse events being fired from inside the or-icon shadowDOM */
|
|
633
|
-
.mdc-list-item__graphic > or-icon {
|
|
634
|
-
pointer-events: none;
|
|
635
|
-
}
|
|
636
|
-
`;
|
|
637
|
-
|
|
638
|
-
@customElement("or-mwc-input")
|
|
639
|
-
export class OrMwcInput extends LitElement {
|
|
640
|
-
|
|
641
|
-
static get styles() {
|
|
642
|
-
return [
|
|
643
|
-
css`${unsafeCSS(iconButtonStyle)}`,
|
|
644
|
-
css`${unsafeCSS(buttonStyle)}`,
|
|
645
|
-
css`${unsafeCSS(buttonFabStyle)}`,
|
|
646
|
-
css`${unsafeCSS(textfieldStyle)}`,
|
|
647
|
-
css`${unsafeCSS(rippleStyle)}`,
|
|
648
|
-
css`${unsafeCSS(lineRippleStyle)}`,
|
|
649
|
-
css`${unsafeCSS(floatingLabelStyle)}`,
|
|
650
|
-
css`${unsafeCSS(formFieldStyle)}`,
|
|
651
|
-
css`${unsafeCSS(checkboxStyle)}`,
|
|
652
|
-
css`${unsafeCSS(radioStyle)}`,
|
|
653
|
-
css`${unsafeCSS(switchStyle)}`,
|
|
654
|
-
css`${unsafeCSS(selectStyle)}`,
|
|
655
|
-
css`${unsafeCSS(listStyle)}`,
|
|
656
|
-
css`${unsafeCSS(menuStyle)}`,
|
|
657
|
-
css`${unsafeCSS(menuSurfaceStyle)}`,
|
|
658
|
-
css`${unsafeCSS(sliderStyle)}`,
|
|
659
|
-
style
|
|
660
|
-
];
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
@property({type: Boolean})
|
|
664
|
-
public focused?: boolean;
|
|
665
|
-
|
|
666
|
-
@property()
|
|
667
|
-
public value?: any;
|
|
668
|
-
|
|
669
|
-
@property({type: String})
|
|
670
|
-
public type?: InputType;
|
|
671
|
-
|
|
672
|
-
@property({type: String})
|
|
673
|
-
public name?: String;
|
|
674
|
-
|
|
675
|
-
@property({type: Boolean})
|
|
676
|
-
public readonly: boolean = false;
|
|
677
|
-
|
|
678
|
-
@property({type: Boolean})
|
|
679
|
-
public required: boolean = false;
|
|
680
|
-
|
|
681
|
-
@property()
|
|
682
|
-
public max?: any;
|
|
683
|
-
|
|
684
|
-
@property()
|
|
685
|
-
public min?: any;
|
|
686
|
-
|
|
687
|
-
@property({type: Number})
|
|
688
|
-
public step?: number;
|
|
689
|
-
|
|
690
|
-
@property({type: Boolean})
|
|
691
|
-
public checked: boolean = false;
|
|
692
|
-
|
|
693
|
-
@property({type: Boolean})
|
|
694
|
-
public indeterminate: boolean = false;
|
|
695
|
-
|
|
696
|
-
@property({type: Number})
|
|
697
|
-
public maxLength?: number;
|
|
698
|
-
|
|
699
|
-
@property({type: Number})
|
|
700
|
-
public minLength?: number;
|
|
701
|
-
|
|
702
|
-
@property({type: Number})
|
|
703
|
-
public rows?: number;
|
|
704
|
-
|
|
705
|
-
@property({type: Number})
|
|
706
|
-
public cols?: number;
|
|
707
|
-
|
|
708
|
-
@property({type: Boolean})
|
|
709
|
-
public multiple: boolean = false;
|
|
710
|
-
|
|
711
|
-
@property({type: String, attribute: true, reflect: false})
|
|
712
|
-
public pattern?: string;
|
|
713
|
-
|
|
714
|
-
@property({type: String})
|
|
715
|
-
public placeHolder?: string;
|
|
716
|
-
|
|
717
|
-
@property({type: Array})
|
|
718
|
-
public options?: any[] | any;
|
|
719
|
-
|
|
720
|
-
@property({type: Boolean})
|
|
721
|
-
public autoSelect?: boolean;
|
|
722
|
-
|
|
723
|
-
@property({type: Object})
|
|
724
|
-
public searchProvider?: (search?: string) => Promise<[any, string][]>
|
|
725
|
-
|
|
726
|
-
@property({type: String})
|
|
727
|
-
public searchLabel = "search"
|
|
728
|
-
|
|
729
|
-
/* STYLING PROPERTIES BELOW */
|
|
730
|
-
|
|
731
|
-
@property({type: String})
|
|
732
|
-
public icon?: string;
|
|
733
|
-
|
|
734
|
-
@property({type: String})
|
|
735
|
-
public iconColor?: string;
|
|
736
|
-
|
|
737
|
-
@property({type: String})
|
|
738
|
-
public iconOn?: string;
|
|
739
|
-
|
|
740
|
-
@property({type: String})
|
|
741
|
-
public iconTrailing?: string;
|
|
742
|
-
|
|
743
|
-
@property({type: Boolean})
|
|
744
|
-
public compact: boolean = false;
|
|
745
|
-
|
|
746
|
-
@property({type: Boolean})
|
|
747
|
-
public comfortable: boolean = false;
|
|
748
|
-
|
|
749
|
-
/* BUTTON STYLES START */
|
|
750
|
-
|
|
751
|
-
@property({type: Boolean})
|
|
752
|
-
public raised: boolean = false;
|
|
753
|
-
|
|
754
|
-
@property({type: Boolean})
|
|
755
|
-
public action: boolean = false;
|
|
756
|
-
|
|
757
|
-
@property({type: Boolean})
|
|
758
|
-
public unElevated: boolean = false;
|
|
759
|
-
|
|
760
|
-
@property({type: Boolean})
|
|
761
|
-
public outlined: boolean = false;
|
|
762
|
-
|
|
763
|
-
@property({type: Boolean})
|
|
764
|
-
public rounded: boolean = false;
|
|
765
|
-
|
|
766
|
-
@property({type: Object})
|
|
767
|
-
public format?: ValueFormat;
|
|
768
|
-
|
|
769
|
-
@property({type: Boolean})
|
|
770
|
-
public disableSliderNumberInput: boolean = false;
|
|
771
|
-
|
|
772
|
-
/* BUTTON STYLES END */
|
|
773
|
-
|
|
774
|
-
/* TEXT INPUT STYLES START */
|
|
775
|
-
|
|
776
|
-
@property({type: Boolean})
|
|
777
|
-
public fullWidth: boolean = false;
|
|
778
|
-
|
|
779
|
-
@property({type: String})
|
|
780
|
-
public helperText?: string;
|
|
781
|
-
|
|
782
|
-
@property({type: Boolean})
|
|
783
|
-
public helperPersistent: boolean = false;
|
|
784
|
-
|
|
785
|
-
@property({type: String, attribute: true})
|
|
786
|
-
public validationMessage?: string;
|
|
787
|
-
|
|
788
|
-
@property({type: Boolean})
|
|
789
|
-
public autoValidate = false;
|
|
790
|
-
|
|
791
|
-
@property({type: Boolean})
|
|
792
|
-
public charCounter: boolean = false;
|
|
793
|
-
|
|
794
|
-
@property({type: String})
|
|
795
|
-
public label?: string;
|
|
796
|
-
|
|
797
|
-
@property({type: Boolean})
|
|
798
|
-
public disabled: boolean = false;
|
|
799
|
-
|
|
800
|
-
@property({type: Boolean})
|
|
801
|
-
public continuous: boolean = false;
|
|
802
|
-
|
|
803
|
-
@property({type: Boolean})
|
|
804
|
-
public resizeVertical: boolean = false;
|
|
805
|
-
|
|
806
|
-
/**
|
|
807
|
-
* Always censure text fields (like a password), and do not allow toggling
|
|
808
|
-
*/
|
|
809
|
-
@property({type: Boolean})
|
|
810
|
-
public censored: boolean = false;
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* Toggles visibility state of the password InputType (true = shown, false = hidden)
|
|
814
|
-
*/
|
|
815
|
-
@property({type: Boolean, reflect: true})
|
|
816
|
-
public advertised: boolean = false;
|
|
817
|
-
|
|
818
|
-
public get nativeValue(): any {
|
|
819
|
-
if (this._mdcComponent) {
|
|
820
|
-
return (this._mdcComponent as any).value;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
/* TEXT INPUT STYLES END */
|
|
825
|
-
|
|
826
|
-
protected _mdcComponent?: MDCComponent<any>;
|
|
827
|
-
protected _mdcComponent2?: MDCComponent<any>;
|
|
828
|
-
protected _selectedIndex = -1;
|
|
829
|
-
protected _menuObserver?: IntersectionObserver;
|
|
830
|
-
protected _tempValue: any;
|
|
831
|
-
@state()
|
|
832
|
-
protected isUiValid = true;
|
|
833
|
-
@state()
|
|
834
|
-
public searchableValue?: string;
|
|
835
|
-
@state()
|
|
836
|
-
protected errorMessage?: string;
|
|
837
|
-
|
|
838
|
-
disconnectedCallback(): void {
|
|
839
|
-
super.disconnectedCallback();
|
|
840
|
-
if (this._mdcComponent) {
|
|
841
|
-
this._mdcComponent.destroy();
|
|
842
|
-
this._mdcComponent = undefined;
|
|
843
|
-
this._menuObserver?.disconnect()
|
|
844
|
-
}
|
|
845
|
-
if (this._mdcComponent2) {
|
|
846
|
-
this._mdcComponent2.destroy();
|
|
847
|
-
this._mdcComponent2 = undefined;
|
|
848
|
-
this._menuObserver?.disconnect();
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
protected shouldUpdate(_changedProperties: PropertyValues) {
|
|
853
|
-
if(_changedProperties.has("indeterminate")) {
|
|
854
|
-
if(this._mdcComponent && this.type === InputType.CHECKBOX){
|
|
855
|
-
(this._mdcComponent as any).indeterminate = this.indeterminate;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
if (_changedProperties.has("disabled")) {
|
|
860
|
-
if (this._mdcComponent) {
|
|
861
|
-
(this._mdcComponent as any).disabled = this.disabled;
|
|
862
|
-
}
|
|
863
|
-
if (this.type === InputType.RANGE && this._mdcComponent2) {
|
|
864
|
-
(this._mdcComponent2 as any).disabled = this.disabled;
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
if (_changedProperties.has("readonly")) {
|
|
869
|
-
if (this._mdcComponent) {
|
|
870
|
-
(this._mdcComponent as any).readonly = this.readonly;
|
|
871
|
-
}
|
|
872
|
-
if (this.type === InputType.RANGE && this._mdcComponent2) {
|
|
873
|
-
(this._mdcComponent2 as any).readonly = this.readonly;
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
if (!this.type && this.value) {
|
|
878
|
-
if (this.value instanceof Date) {
|
|
879
|
-
this.type = InputType.DATETIME;
|
|
880
|
-
} else if (typeof(this.value) === "boolean") {
|
|
881
|
-
this.type = InputType.CHECKBOX;
|
|
882
|
-
} else if (typeof(this.value) === "number") {
|
|
883
|
-
this.type = InputType.NUMBER;
|
|
884
|
-
} else if (typeof(this.value) === "string") {
|
|
885
|
-
this.type = InputType.TEXT;
|
|
886
|
-
} else {
|
|
887
|
-
this.type = InputType.JSON;
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
return true;
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
public focus() {
|
|
894
|
-
if (this.type === InputType.RANGE && this._mdcComponent2) {
|
|
895
|
-
(this._mdcComponent2 as any).focus();
|
|
896
|
-
} else if (this._mdcComponent && typeof (this._mdcComponent as any).focus === "function") {
|
|
897
|
-
(this._mdcComponent as any).focus();
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
protected render() {
|
|
903
|
-
|
|
904
|
-
if (this.type) {
|
|
905
|
-
|
|
906
|
-
const showLabel = !this.fullWidth && this.label;
|
|
907
|
-
let outlined = !this.fullWidth && this.outlined;
|
|
908
|
-
let hasHelper = !!this.helperText;
|
|
909
|
-
const showValidationMessage = !this.isUiValid && (!!this.errorMessage || !!this.validationMessage);
|
|
910
|
-
const helperClasses = {
|
|
911
|
-
"mdc-text-field-helper-text--persistent": !showValidationMessage && this.helperPersistent,
|
|
912
|
-
"mdc-text-field-helper-text--validation-msg": showValidationMessage,
|
|
913
|
-
};
|
|
914
|
-
const hasValue = (this.value !== null && this.value !== undefined) || this.value === false;
|
|
915
|
-
let labelTemplate = showLabel ? html`<span class="mdc-floating-label ${hasValue ? "mdc-floating-label--float-above" : ""}" id="label">${this.label}</span>` : undefined;
|
|
916
|
-
|
|
917
|
-
switch (this.type) {
|
|
918
|
-
case InputType.RADIO:
|
|
919
|
-
const optsRadio = this.resolveOptions(this.options);
|
|
920
|
-
this._selectedIndex = -1;
|
|
921
|
-
return html`
|
|
922
|
-
<div class="mdc-radio-container">
|
|
923
|
-
${optsRadio ? optsRadio.map(([optValue, optDisplay], index) => {
|
|
924
|
-
if (this.value === optValue) {
|
|
925
|
-
this._selectedIndex = index;
|
|
926
|
-
}
|
|
927
|
-
return html`
|
|
928
|
-
<div id="field" class="mdc-form-field">
|
|
929
|
-
<div class="mdc-radio">
|
|
930
|
-
<input type="radio"
|
|
931
|
-
id="elem-${optValue}"
|
|
932
|
-
name="${ifDefined(this.name)}"
|
|
933
|
-
value="${optValue}"
|
|
934
|
-
?checked="${this.value && this.value.includes(optValue)}"
|
|
935
|
-
?required="${this.required}"
|
|
936
|
-
?disabled="${this.disabled || this.readonly}"
|
|
937
|
-
@change="${(e: Event) => this.onValueChange((e.target as HTMLInputElement), optValue)}"
|
|
938
|
-
class="mdc-radio__native-control"/>
|
|
939
|
-
<div class="mdc-radio__background">
|
|
940
|
-
<div class="mdc-radio__outer-circle"></div>
|
|
941
|
-
<div class="mdc-radio__inner-circle"></div>
|
|
942
|
-
</div>
|
|
943
|
-
<div class="mdc-radio__ripple"></div>
|
|
944
|
-
</div>
|
|
945
|
-
<label for="elem-${optValue}"><or-translate value="${optDisplay}"></or-translate></label>
|
|
946
|
-
</div>
|
|
947
|
-
|
|
948
|
-
`;
|
|
949
|
-
}) : ``}
|
|
950
|
-
</div>
|
|
951
|
-
`;
|
|
952
|
-
case InputType.SWITCH:
|
|
953
|
-
const classesSwitch = {
|
|
954
|
-
"mdc-switch--disabled": this.disabled || this.readonly,
|
|
955
|
-
"mdc-switch--full-width": this.fullWidth,
|
|
956
|
-
"mdc-switch--checked": this.value,
|
|
957
|
-
};
|
|
958
|
-
|
|
959
|
-
return html`
|
|
960
|
-
<span id="wrapper">
|
|
961
|
-
${this.label ? html`<label for="elem" class="${this.disabled ? "mdc-switch--disabled" : ""}">${this.label}</label>` : ``}
|
|
962
|
-
<div id="component" class="mdc-switch ${classMap(classesSwitch)}">
|
|
963
|
-
<div class="mdc-switch__track"></div>
|
|
964
|
-
<div class="mdc-switch__thumb-underlay">
|
|
965
|
-
<div class="mdc-switch__thumb">
|
|
966
|
-
<input type="checkbox" id="elem" class="mdc-switch__native-control"
|
|
967
|
-
?checked="${this.value}"
|
|
968
|
-
?required="${this.required}"
|
|
969
|
-
?disabled="${this.disabled || this.readonly}"
|
|
970
|
-
@change="${(e: Event) => this.onValueChange((e.target as HTMLInputElement), (e.target as HTMLInputElement).checked)}"
|
|
971
|
-
role="switch">
|
|
972
|
-
</div>
|
|
973
|
-
</div>
|
|
974
|
-
</div>
|
|
975
|
-
</span>
|
|
976
|
-
`;
|
|
977
|
-
case InputType.LIST:
|
|
978
|
-
const classesList = {
|
|
979
|
-
"mdc-select--outlined": outlined,
|
|
980
|
-
"mdc-select--disabled": this.disabled,
|
|
981
|
-
"mdc-select--required": this.required,
|
|
982
|
-
"mdc-select--dense": false, // this.dense,
|
|
983
|
-
"mdc-select--no-label": !this.label,
|
|
984
|
-
"mdc-select--with-leading-icon": !!this.icon
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
const optsList = this.resolveOptions(this.options);
|
|
988
|
-
this._selectedIndex = -1;
|
|
989
|
-
return html`
|
|
990
|
-
<div id="component" class="mdc-list mdc-select ${classMap(classesList)}" @MDCList:action="${(e: MDCListActionEvent) => this.onValueChange(undefined, e.detail.index === -1 ? undefined : Array.isArray(this.options![e.detail.index]) ? this.options![e.detail.index][0] : this.options![e.detail.index])}">
|
|
991
|
-
<ul class="mdc-list">
|
|
992
|
-
${optsList ? optsList.map(([optValue, optDisplay], index) => {
|
|
993
|
-
if (this.value === optValue) {
|
|
994
|
-
this._selectedIndex = index;
|
|
995
|
-
}
|
|
996
|
-
// todo: it's not actually putting the mdc-list-item--selected class on even when this.value === optValue...
|
|
997
|
-
return html`<li class="${classMap({"mdc-list-item": true, "mdc-list-item--selected": this.value === optValue})}" role="option" data-value="${optValue}"><or-translate value="${optDisplay}"></or-translate></li>`;
|
|
998
|
-
}) : ``}
|
|
999
|
-
</ul>
|
|
1000
|
-
</div>
|
|
1001
|
-
`;
|
|
1002
|
-
case InputType.SELECT:
|
|
1003
|
-
const classes = {
|
|
1004
|
-
"mdc-select--outlined": outlined,
|
|
1005
|
-
"mdc-select--filled": !outlined,
|
|
1006
|
-
"mdc-select--disabled": this.disabled || this.readonly,
|
|
1007
|
-
"mdc-select--required": this.required,
|
|
1008
|
-
"mdc-select--dense": false, // this.dense,
|
|
1009
|
-
"dense-comfortable": this.comfortable,
|
|
1010
|
-
"mdc-select--no-label": !this.label,
|
|
1011
|
-
"mdc-select--with-leading-icon": !!this.icon,
|
|
1012
|
-
"or-mwc-input--rounded": this.rounded
|
|
1013
|
-
|
|
1014
|
-
};
|
|
1015
|
-
|
|
1016
|
-
let opts: [any, string][] | Promise<[any, string][]>;
|
|
1017
|
-
if(this.searchProvider != undefined) {
|
|
1018
|
-
opts = this.searchProvider(this.searchableValue);
|
|
1019
|
-
} else {
|
|
1020
|
-
opts = this.resolveOptions(this.options)!;
|
|
1021
|
-
}
|
|
1022
|
-
const itemClickHandler: (ev: MouseEvent, item: ListItem) => void = (ev, item) => {
|
|
1023
|
-
const value = item.value;
|
|
1024
|
-
|
|
1025
|
-
if (this.multiple) {
|
|
1026
|
-
ev.stopPropagation();
|
|
1027
|
-
const inputValue = this._tempValue ?? (Array.isArray(this.value) ? [...this.value] : this.value !== undefined ? [this.value] : []);
|
|
1028
|
-
|
|
1029
|
-
const index = inputValue.findIndex((v: any) => v === value);
|
|
1030
|
-
if (index >= 0) {
|
|
1031
|
-
inputValue.splice(index, 1);
|
|
1032
|
-
} else {
|
|
1033
|
-
inputValue.push(value);
|
|
1034
|
-
}
|
|
1035
|
-
const listItemEl = (ev.composedPath()[0] as HTMLElement).closest("li") as HTMLElement,
|
|
1036
|
-
iconEl = listItemEl.getElementsByTagName("or-icon")[0] as OrIcon;
|
|
1037
|
-
if (listItemEl) {
|
|
1038
|
-
if (index >= 0) {
|
|
1039
|
-
listItemEl.classList.remove("mdc-list-item--selected");
|
|
1040
|
-
} else {
|
|
1041
|
-
listItemEl.classList.add("mdc-list-item--selected");
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
if (iconEl) {
|
|
1045
|
-
iconEl.icon = index >= 0 ? "checkbox-blank-outline" : "checkbox-marked";
|
|
1046
|
-
}
|
|
1047
|
-
this._tempValue = inputValue;
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
// A narrowed down list with search, or a different asynchronous approach does not always trigger @MDCSelect:change,
|
|
1051
|
-
// so using itemClickHandler instead to let it trigger anyway.
|
|
1052
|
-
else if(this.searchProvider != undefined || !Array.isArray(opts)) {
|
|
1053
|
-
this.onValueChange(undefined, item.value);
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
};
|
|
1057
|
-
|
|
1058
|
-
const menuCloseHandler = () => {
|
|
1059
|
-
const v = (this._tempValue ?? this.value);
|
|
1060
|
-
window.setTimeout(() => {
|
|
1061
|
-
if (this._mdcComponent) {
|
|
1062
|
-
// Hack to stop label moving down when there is a value set
|
|
1063
|
-
(this._mdcComponent as any).foundation.adapter.floatLabel(v && (!Array.isArray(v) || v.length > 0));
|
|
1064
|
-
}
|
|
1065
|
-
});
|
|
1066
|
-
|
|
1067
|
-
if (!this._tempValue) {
|
|
1068
|
-
return;
|
|
1069
|
-
}
|
|
1070
|
-
const val = [...this._tempValue];
|
|
1071
|
-
this._tempValue = undefined;
|
|
1072
|
-
this.onValueChange(undefined, val);
|
|
1073
|
-
};
|
|
1074
|
-
|
|
1075
|
-
const listTemplate = (options: [any, string][]) => {
|
|
1076
|
-
if(this.searchProvider != undefined && (!options || options.length == 0)) {
|
|
1077
|
-
return html`<span class="mdc-text-field-helper-line" style="margin: 8px 8px 8px 0;">${i18next.t('noResults')}</span>`
|
|
1078
|
-
} else {
|
|
1079
|
-
return getListTemplate(
|
|
1080
|
-
this.multiple ? ListType.MULTI_TICK : ListType.SELECT,
|
|
1081
|
-
html`${options?.map(([optValue, optDisplay], index) => {
|
|
1082
|
-
return getItemTemplate(
|
|
1083
|
-
{
|
|
1084
|
-
text: optDisplay,
|
|
1085
|
-
value: optValue
|
|
1086
|
-
},
|
|
1087
|
-
index,
|
|
1088
|
-
Array.isArray(this.value) ? this.value as any[] : this.value ? [this.value as any] : [],
|
|
1089
|
-
this.multiple ? ListType.MULTI_TICK : ListType.SELECT,
|
|
1090
|
-
false,
|
|
1091
|
-
itemClickHandler
|
|
1092
|
-
);
|
|
1093
|
-
})}`,
|
|
1094
|
-
false,
|
|
1095
|
-
undefined
|
|
1096
|
-
);
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
return html`
|
|
1101
|
-
<div id="component"
|
|
1102
|
-
class="mdc-select ${classMap(classes)}"
|
|
1103
|
-
@MDCSelect:change="${async (e: MDCSelectEvent) => {
|
|
1104
|
-
const options: [any, string][] = (Array.isArray(opts) ? opts : await opts);
|
|
1105
|
-
this.onValueChange(undefined, e.detail.index === -1 ? undefined : Array.isArray(options[e.detail.index]) ? options[e.detail.index][0] : options[e.detail.index]);
|
|
1106
|
-
}}">
|
|
1107
|
-
<div class="mdc-select__anchor" role="button"
|
|
1108
|
-
aria-haspopup="listbox"
|
|
1109
|
-
aria-expanded="false"
|
|
1110
|
-
aria-disabled="${""+(this.disabled || this.readonly)}"
|
|
1111
|
-
aria-labelledby="label selected-text">
|
|
1112
|
-
${!outlined ? html`<span class="mdc-select__ripple"></span>` : undefined}
|
|
1113
|
-
${outlined ? this.renderOutlined(labelTemplate) : labelTemplate}
|
|
1114
|
-
<span class="mdc-select__selected-text-container">
|
|
1115
|
-
<span id="selected-text" class="mdc-select__selected-text"></span>
|
|
1116
|
-
</span>
|
|
1117
|
-
<span class="mdc-select__dropdown-icon">
|
|
1118
|
-
<svg
|
|
1119
|
-
class="mdc-select__dropdown-icon-graphic"
|
|
1120
|
-
viewBox="7 10 10 5">
|
|
1121
|
-
<polygon
|
|
1122
|
-
class="mdc-select__dropdown-icon-inactive"
|
|
1123
|
-
stroke="none"
|
|
1124
|
-
fill-rule="evenodd"
|
|
1125
|
-
points="7 10 12 15 17 10">
|
|
1126
|
-
</polygon>
|
|
1127
|
-
<polygon
|
|
1128
|
-
class="mdc-select__dropdown-icon-active"
|
|
1129
|
-
stroke="none"
|
|
1130
|
-
fill-rule="evenodd"
|
|
1131
|
-
points="7 15 12 10 17 15">
|
|
1132
|
-
</polygon>
|
|
1133
|
-
</svg>
|
|
1134
|
-
</span>
|
|
1135
|
-
${!outlined ? html`<div class="mdc-line-ripple"></div>` : ``}
|
|
1136
|
-
</div>
|
|
1137
|
-
<div id="mdc-select-menu" class="mdc-select__menu mdc-menu mdc-menu-surface mdc-menu-surface--fixed ${this.searchProvider != undefined ? 'mdc-menu__searchable' : undefined}" @MDCMenuSurface:closed="${menuCloseHandler}">
|
|
1138
|
-
${when(this.searchProvider != undefined, () => html`
|
|
1139
|
-
<label id="select-searchable" class="mdc-text-field mdc-text-field--filled">
|
|
1140
|
-
<span class="mdc-floating-label" style="color: rgba(0, 0, 0, 0.6); text-transform: capitalize; visibility: ${this.searchableValue ? 'hidden' : 'visible'}" id="my-label-id">
|
|
1141
|
-
<or-translate .value="${this.searchLabel}"></or-translate>
|
|
1142
|
-
</span>
|
|
1143
|
-
<input class="mdc-text-field__input" type="text"
|
|
1144
|
-
@keyup="${(e: KeyboardEvent) => this.searchableValue = (e.target as HTMLInputElement).value}"
|
|
1145
|
-
/>
|
|
1146
|
-
</label>
|
|
1147
|
-
`)}
|
|
1148
|
-
${when(Array.isArray(opts), () => {
|
|
1149
|
-
return listTemplate(opts as [any, string][]);
|
|
1150
|
-
}, () => {
|
|
1151
|
-
return until(new Promise(async (resolve) => {
|
|
1152
|
-
resolve(listTemplate(await opts));
|
|
1153
|
-
}), html`<span class="mdc-text-field-helper-line" style="margin: 8px 8px 8px 0;">${i18next.t('loading')}</span>`)
|
|
1154
|
-
})}
|
|
1155
|
-
</div>
|
|
1156
|
-
${hasHelper || showValidationMessage ? html`
|
|
1157
|
-
<p id="component-helper-text" class="mdc-select-helper-text ${classMap(helperClasses)}" aria-hidden="true">
|
|
1158
|
-
${showValidationMessage ? this.errorMessage || this.validationMessage : this.helperText}
|
|
1159
|
-
</p>` : ``}
|
|
1160
|
-
</div>
|
|
1161
|
-
`;
|
|
1162
|
-
case InputType.BUTTON_TOGGLE:
|
|
1163
|
-
return html`
|
|
1164
|
-
<button id="component" class="mdc-icon-button ${this.value ? "mdc-icon-button--on" : ""}"
|
|
1165
|
-
?readonly="${this.readonly}"
|
|
1166
|
-
?disabled="${this.disabled}"
|
|
1167
|
-
@MDCIconButtonToggle:change="${(evt: CustomEvent<MDCIconButtonToggleEventDetail>) => this.onValueChange(undefined, evt.detail.isOn)}">
|
|
1168
|
-
${this.icon ? html`<or-icon class="mdc-icon-button__icon" aria-hidden="true" icon="${this.icon}"></or-icon>` : ``}
|
|
1169
|
-
${this.iconOn ? html`<or-icon class="mdc-icon-button__icon mdc-icon-button__icon--on" aria-hidden="true" icon="${this.iconOn}"></or-icon>` : ``}
|
|
1170
|
-
</button>
|
|
1171
|
-
`;
|
|
1172
|
-
case InputType.BUTTON:
|
|
1173
|
-
case InputType.BUTTON_MOMENTARY: {
|
|
1174
|
-
|
|
1175
|
-
const onMouseDown = (ev: MouseEvent) => {
|
|
1176
|
-
if (this.disabled) {
|
|
1177
|
-
ev.stopPropagation();
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
if (isMomentary) this.dispatchEvent(new OrInputChangedEvent(true, null))
|
|
1181
|
-
};
|
|
1182
|
-
const onMouseUp = (ev: MouseEvent) => {
|
|
1183
|
-
if (this.disabled) {
|
|
1184
|
-
ev.stopPropagation();
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
if (isMomentary) this.dispatchEvent(new OrInputChangedEvent(false, true))
|
|
1188
|
-
};
|
|
1189
|
-
const onClick = (ev: MouseEvent) => {
|
|
1190
|
-
if (this.disabled) {
|
|
1191
|
-
ev.stopPropagation();
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
if (!isMomentary) this.dispatchEvent(new OrInputChangedEvent(true, null))
|
|
1195
|
-
};
|
|
1196
|
-
|
|
1197
|
-
const isMomentary = this.type === InputType.BUTTON_MOMENTARY;
|
|
1198
|
-
const isIconButton = !this.action && !this.label;
|
|
1199
|
-
// If no action, label or icons are given, show as a circle.
|
|
1200
|
-
if (isIconButton && !this.iconTrailing && !this.icon ) {
|
|
1201
|
-
this.icon = "circle"
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
const classes = {
|
|
1205
|
-
"mdc-icon-button": isIconButton,
|
|
1206
|
-
"mdc-fab": !isIconButton && this.action,
|
|
1207
|
-
"mdc-fab--extended": !isIconButton && this.action && !!this.label,
|
|
1208
|
-
"mdc-fab--mini": !isIconButton && this.action && (this.compact || this.comfortable),
|
|
1209
|
-
"mdc-button": !isIconButton && !this.action,
|
|
1210
|
-
"mdc-button--raised": !isIconButton && !this.action && this.raised,
|
|
1211
|
-
"mdc-button--unelevated": !isIconButton && !this.action && this.unElevated,
|
|
1212
|
-
"mdc-button--outlined": !isIconButton && !this.action && (this.outlined || isMomentary),
|
|
1213
|
-
"mdc-button--rounded": !isIconButton && !this.action && this.rounded,
|
|
1214
|
-
"mdc-button--fullwidth": this.fullWidth,
|
|
1215
|
-
};
|
|
1216
|
-
return html`
|
|
1217
|
-
<button id="component" class="${classMap(classes)}"
|
|
1218
|
-
?readonly="${this.readonly}"
|
|
1219
|
-
?disabled="${this.disabled}"
|
|
1220
|
-
@click="${(ev: MouseEvent) => onClick(ev)}"
|
|
1221
|
-
@mousedown="${(ev: MouseEvent) => onMouseDown(ev)}" @mouseup="${(ev: MouseEvent) => onMouseUp(ev)}">
|
|
1222
|
-
${!isIconButton ? html`<div class="mdc-button__ripple"></div>` : ``}
|
|
1223
|
-
${this.icon ? html`<or-icon class="${isIconButton ? "" : this.action ? "mdc-fab__icon" : "mdc-button__icon"}" aria-hidden="true" icon="${this.icon}"></or-icon>` : ``}
|
|
1224
|
-
${this.label ? html`<span class="${this.action ? "mdc-fab__label" : "mdc-button__label"}"><or-translate .value="${this.label}"></or-translate></span>` : ``}
|
|
1225
|
-
${!isIconButton && this.iconTrailing ? html`<or-icon class="${this.action ? "mdc-fab__icon" : "mdc-button__icon"}" aria-hidden="true" icon="${this.iconTrailing}"></or-icon>` : ``}
|
|
1226
|
-
</button>
|
|
1227
|
-
`;
|
|
1228
|
-
}
|
|
1229
|
-
case InputType.CHECKBOX_LIST:
|
|
1230
|
-
if (!Array.isArray(this.value)) {
|
|
1231
|
-
if (this.value === null || this.value === undefined) {
|
|
1232
|
-
this.value = [];
|
|
1233
|
-
} else {
|
|
1234
|
-
this.value = [this.value];
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
const optsCheckboxList = this.resolveOptions(this.options);
|
|
1238
|
-
this._selectedIndex = -1;
|
|
1239
|
-
return html`
|
|
1240
|
-
<div class="mdc-checkbox-list">
|
|
1241
|
-
${optsCheckboxList ? optsCheckboxList.map(([optValue, optDisplay], index) => {
|
|
1242
|
-
if (this.value === optValue) {
|
|
1243
|
-
this._selectedIndex = index;
|
|
1244
|
-
}
|
|
1245
|
-
return html`
|
|
1246
|
-
<div id="field" class="mdc-form-field">
|
|
1247
|
-
<div id="component" class="mdc-checkbox">
|
|
1248
|
-
<input type="checkbox"
|
|
1249
|
-
?checked="${this.value && this.value.includes(optValue)}"
|
|
1250
|
-
?required="${this.required}"
|
|
1251
|
-
name="${optValue}"
|
|
1252
|
-
?disabled="${this.disabled || this.readonly}"
|
|
1253
|
-
@change="${(e: Event) => {
|
|
1254
|
-
let val: any[] = this.value;
|
|
1255
|
-
if ((e.target as HTMLInputElement).checked) {
|
|
1256
|
-
if (!val.includes(optValue)) {
|
|
1257
|
-
val = [optValue,...val];
|
|
1258
|
-
}
|
|
1259
|
-
} else {
|
|
1260
|
-
val = val.filter((v: any) => v !== optValue);
|
|
1261
|
-
}
|
|
1262
|
-
this.onValueChange((e.target as HTMLInputElement), val);
|
|
1263
|
-
}}"
|
|
1264
|
-
class="mdc-checkbox__native-control" id="elem-${optValue}"/>
|
|
1265
|
-
|
|
1266
|
-
<label for="elem-${optValue}"><or-translate value="${optDisplay}"></or-translate></label>
|
|
1267
|
-
|
|
1268
|
-
</div>
|
|
1269
|
-
</div>
|
|
1270
|
-
|
|
1271
|
-
`;
|
|
1272
|
-
}) : ``}
|
|
1273
|
-
</div>
|
|
1274
|
-
`;
|
|
1275
|
-
case InputType.CHECKBOX:
|
|
1276
|
-
let classList = {
|
|
1277
|
-
"mdc-checkbox": true,
|
|
1278
|
-
"mdc-checkbox--disabled": this.disabled || this.readonly
|
|
1279
|
-
};
|
|
1280
|
-
return html`
|
|
1281
|
-
<div id="field" class="mdc-form-field">
|
|
1282
|
-
<div id="component" class="${classMap(classList)}">
|
|
1283
|
-
<input type="checkbox"
|
|
1284
|
-
id="elem"
|
|
1285
|
-
data-indeterminate="${this.indeterminate}"
|
|
1286
|
-
?checked="${this.value}"
|
|
1287
|
-
?required="${this.required}"
|
|
1288
|
-
?disabled="${this.disabled || this.readonly}"
|
|
1289
|
-
@change="${(e: Event) => this.onValueChange((e.target as HTMLInputElement), (e.target as HTMLInputElement).checked)}"
|
|
1290
|
-
class="mdc-checkbox__native-control" />
|
|
1291
|
-
<div class="mdc-checkbox__background">
|
|
1292
|
-
<svg class="mdc-checkbox__checkmark" viewBox="0 0 24 24">
|
|
1293
|
-
<path class="mdc-checkbox__checkmark-path" fill="none" d="M1.73,12.91 8.1,19.28 22.79,4.59"></path>
|
|
1294
|
-
</svg>
|
|
1295
|
-
<div class="mdc-checkbox__mixedmark"></div>
|
|
1296
|
-
</div>
|
|
1297
|
-
<div class="mdc-checkbox__ripple"></div>
|
|
1298
|
-
</div>
|
|
1299
|
-
<label class="mdc-checkbox-circle" for="elem">${this.label}</label>
|
|
1300
|
-
</div>
|
|
1301
|
-
`;
|
|
1302
|
-
case InputType.COLOUR:
|
|
1303
|
-
return html`
|
|
1304
|
-
<div id="component" style="width: 100%; display: inline-flex; align-items: center; padding: 8px 0;">
|
|
1305
|
-
<input type="color" id="elem" style="border: none; height: 31px; width: 31px; padding: 1px 3px; min-height: 22px; min-width: 30px;cursor: pointer" value="${this.value}"
|
|
1306
|
-
?disabled="${this.disabled || this.readonly}"
|
|
1307
|
-
?required="${this.required}"
|
|
1308
|
-
@change="${(e: any) => this.onValueChange((e.target as HTMLInputElement), (e.target as HTMLInputElement).value)}"
|
|
1309
|
-
/>
|
|
1310
|
-
<label style="margin-left: 10px; cursor: pointer" for="elem">${this.label}</label>
|
|
1311
|
-
</div>
|
|
1312
|
-
`
|
|
1313
|
-
case InputType.NUMBER:
|
|
1314
|
-
case InputType.RANGE:
|
|
1315
|
-
case InputType.DATE:
|
|
1316
|
-
case InputType.DATETIME:
|
|
1317
|
-
case InputType.TIME:
|
|
1318
|
-
case InputType.MONTH:
|
|
1319
|
-
case InputType.WEEK:
|
|
1320
|
-
case InputType.EMAIL:
|
|
1321
|
-
case InputType.PASSWORD:
|
|
1322
|
-
case InputType.TELEPHONE:
|
|
1323
|
-
case InputType.URL:
|
|
1324
|
-
case InputType.TEXT:
|
|
1325
|
-
case InputType.TEXTAREA:
|
|
1326
|
-
case InputType.JSON:
|
|
1327
|
-
case InputType.JSON_OBJECT: {
|
|
1328
|
-
// The following HTML input types require the values as specially formatted strings
|
|
1329
|
-
let valMinMax: [any, any, any] = [this.value === undefined || this.value === null ? undefined : this.value, this.min, this.max];
|
|
1330
|
-
|
|
1331
|
-
if (valMinMax.some((v) => typeof (v) !== "string")) {
|
|
1332
|
-
|
|
1333
|
-
if (this.type === InputType.JSON || this.type === InputType.JSON_OBJECT) {
|
|
1334
|
-
if (valMinMax[0] !== undefined) {
|
|
1335
|
-
if (typeof valMinMax[0] !== "string" || valMinMax[0] === null) {
|
|
1336
|
-
try {
|
|
1337
|
-
valMinMax[0] = JSON.stringify(valMinMax[0], null, 2);
|
|
1338
|
-
} catch (e) {
|
|
1339
|
-
console.warn("Failed to parse JSON expression for input control");
|
|
1340
|
-
valMinMax[0] = "";
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
} else {
|
|
1344
|
-
valMinMax[0] = "";
|
|
1345
|
-
}
|
|
1346
|
-
} else {
|
|
1347
|
-
|
|
1348
|
-
const format = this.format ? {...this.format} : {};
|
|
1349
|
-
|
|
1350
|
-
switch (this.type) {
|
|
1351
|
-
case InputType.TIME:
|
|
1352
|
-
format.asDate = true;
|
|
1353
|
-
format.hour12 = false;
|
|
1354
|
-
format.timeStyle = this.step && this.step < 60 ? ValueFormatStyleRepresentation.MEDIUM : ValueFormatStyleRepresentation.SHORT;
|
|
1355
|
-
break;
|
|
1356
|
-
case InputType.DATE:
|
|
1357
|
-
format.asDate = true;
|
|
1358
|
-
format.momentJsFormat = "YYYY-MM-DD";
|
|
1359
|
-
break;
|
|
1360
|
-
case InputType.WEEK:
|
|
1361
|
-
format.asDate = true;
|
|
1362
|
-
format.momentJsFormat = "YYYY-[W]WW";
|
|
1363
|
-
break;
|
|
1364
|
-
case InputType.MONTH:
|
|
1365
|
-
format.asDate = true;
|
|
1366
|
-
format.momentJsFormat = "YYYY-MM";
|
|
1367
|
-
break;
|
|
1368
|
-
case InputType.DATETIME:
|
|
1369
|
-
format.asDate = true;
|
|
1370
|
-
format.momentJsFormat = "YYYY-MM-DDTHH:mm";
|
|
1371
|
-
break;
|
|
1372
|
-
case InputType.NUMBER:
|
|
1373
|
-
format.maximumFractionDigits ??= 20; // default according to Web documentation
|
|
1374
|
-
break;
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
// Numbers/dates must be in english locale without commas etc.
|
|
1378
|
-
format.useGrouping = false;
|
|
1379
|
-
valMinMax = valMinMax.map((val) => val !== undefined ? Util.getValueAsString(val, () => format, "en-GB") : undefined) as [any,any,any];
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
let inputElem: TemplateResult | undefined;
|
|
1384
|
-
let label = this.label;
|
|
1385
|
-
let type = this.type;
|
|
1386
|
-
let componentId = "component";
|
|
1387
|
-
|
|
1388
|
-
if (this.type === InputType.RANGE) {
|
|
1389
|
-
// Change vars so number input can be included alongside the slider
|
|
1390
|
-
label = undefined;
|
|
1391
|
-
outlined = false;
|
|
1392
|
-
hasHelper = false;
|
|
1393
|
-
type = InputType.NUMBER;
|
|
1394
|
-
componentId = "number";
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
if (!(this.type === InputType.RANGE && this.disableSliderNumberInput)) {
|
|
1398
|
-
|
|
1399
|
-
// Handle password toggling logic
|
|
1400
|
-
if(this.censored) type = InputType.PASSWORD;
|
|
1401
|
-
if(this.type === InputType.PASSWORD && this.advertised) type = InputType.TEXT;
|
|
1402
|
-
|
|
1403
|
-
const classes = {
|
|
1404
|
-
"mdc-text-field": true,
|
|
1405
|
-
"mdc-text-field--invalid": !this.valid,
|
|
1406
|
-
"mdc-text-field--filled": !outlined,
|
|
1407
|
-
"mdc-text-field--outlined": outlined,
|
|
1408
|
-
"mdc-text-field--textarea": type === InputType.TEXTAREA || type === InputType.JSON || type === InputType.JSON_OBJECT,
|
|
1409
|
-
"mdc-text-field--disabled": this.disabled,
|
|
1410
|
-
"mdc-text-field--fullwidth": this.fullWidth && !outlined,
|
|
1411
|
-
"dense-comfortable": this.comfortable && !(type === InputType.TEXTAREA || type === InputType.JSON || type === InputType.JSON_OBJECT),
|
|
1412
|
-
"dense-compact": !this.comfortable && this.compact,
|
|
1413
|
-
"mdc-text-field--label-floating": hasValue,
|
|
1414
|
-
"mdc-text-field--no-label": !this.label,
|
|
1415
|
-
"mdc-text-field--with-leading-icon": !!this.icon,
|
|
1416
|
-
"mdc-text-field--with-trailing-icon": !!this.iconTrailing,
|
|
1417
|
-
"or-mwc-input--rounded": this.rounded
|
|
1418
|
-
};
|
|
1419
|
-
|
|
1420
|
-
inputElem = type === InputType.TEXTAREA || type === InputType.JSON || type === InputType.JSON_OBJECT
|
|
1421
|
-
? html`
|
|
1422
|
-
<textarea id="elem" class="mdc-text-field__input ${this.resizeVertical ? "resize-vertical" : ""}" ?required="${this.required}"
|
|
1423
|
-
?readonly="${this.readonly}" ?disabled="${this.disabled}" minlength="${ifDefined(this.minLength)}"
|
|
1424
|
-
maxlength="${ifDefined(this.maxLength)}" rows="${this.rows ? this.rows : 5}"
|
|
1425
|
-
cols="${ifDefined(this.cols)}" aria-label="${ifDefined(label)}"
|
|
1426
|
-
aria-labelledby="${ifDefined(label ? "label" : undefined)}"
|
|
1427
|
-
@change="${(e: Event) => this.onValueChange((e.target as HTMLTextAreaElement), (e.target as HTMLTextAreaElement).value)}">${valMinMax[0] ? valMinMax[0] : ""}</textarea>`
|
|
1428
|
-
: html`
|
|
1429
|
-
<input type="${type}" id="elem" aria-labelledby="${ifDefined(label ? "label" : undefined)}"
|
|
1430
|
-
class="mdc-text-field__input" ?required="${this.required}" ?readonly="${this.readonly}"
|
|
1431
|
-
?disabled="${this.disabled}" min="${ifDefined(valMinMax[1])}" max="${ifDefined(valMinMax[2])}"
|
|
1432
|
-
step="${this.step ? this.step : "any"}" minlength="${ifDefined(this.minLength)}" pattern="${ifDefined(this.pattern)}"
|
|
1433
|
-
maxlength="${ifDefined(this.maxLength)}" placeholder="${ifDefined(this.placeHolder)}"
|
|
1434
|
-
.value="${valMinMax[0] !== null && valMinMax[0] !== undefined ? valMinMax[0] : ""}"
|
|
1435
|
-
@keydown="${(e: KeyboardEvent) => {
|
|
1436
|
-
if ((e.code === "Enter" || e.code === "NumpadEnter")) {
|
|
1437
|
-
this.onValueChange((e.target as HTMLInputElement), (e.target as HTMLInputElement).value, true);
|
|
1438
|
-
}}}"
|
|
1439
|
-
@blur="${(e: Event) => {if ((e.target as HTMLInputElement).value === "") this.reportValidity()}}"
|
|
1440
|
-
@change="${(e: Event) => this.onValueChange((e.target as HTMLInputElement), (e.target as HTMLInputElement).value)}" />`;
|
|
1441
|
-
|
|
1442
|
-
inputElem = html`
|
|
1443
|
-
<label id="${componentId}" class="${classMap(classes)}">
|
|
1444
|
-
${this.icon ? html`<or-icon class="mdc-text-field__icon mdc-text-field__icon--leading" style="color: ${this.iconColor ? "#" + this.iconColor : "unset"}" aria-hidden="true" icon="${this.icon}"></or-icon>` : ``}
|
|
1445
|
-
${outlined ? `` : html`<span class="mdc-text-field__ripple"></span>`}
|
|
1446
|
-
${inputElem}
|
|
1447
|
-
${outlined ? this.renderOutlined(labelTemplate) : labelTemplate}
|
|
1448
|
-
${outlined ? `` : html`<span class="mdc-line-ripple"></span>`}
|
|
1449
|
-
${this.type === InputType.PASSWORD && !this.censored ? html`<or-icon class="mdc-text-field__icon mdc-text-field__icon--trailing" aria-hidden="true" icon=${this.advertised ? 'eye' : 'eye-off'} style="pointer-events: auto;" @click=${() => this.advertised = !this.advertised}></or-icon>` : ``}
|
|
1450
|
-
${this.iconTrailing ? html`<or-icon class="mdc-text-field__icon mdc-text-field__icon--trailing" aria-hidden="true" icon="${this.iconTrailing}"></or-icon>` : ``}
|
|
1451
|
-
</label>
|
|
1452
|
-
${hasHelper || showValidationMessage ? html`
|
|
1453
|
-
<div class="mdc-text-field-helper-line">
|
|
1454
|
-
<div class="mdc-text-field-helper-text ${classMap(helperClasses)}">${showValidationMessage ? this.errorMessage || this.validationMessage : this.helperText}</div>
|
|
1455
|
-
${this.charCounter && !this.readonly ? html`<div class="mdc-text-field-character-counter"></div>` : ``}
|
|
1456
|
-
</div>
|
|
1457
|
-
` : ``}
|
|
1458
|
-
`;
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
if (this.type === InputType.RANGE) {
|
|
1462
|
-
|
|
1463
|
-
const classes = {
|
|
1464
|
-
"mdc-slider": true,
|
|
1465
|
-
"mdc-slider--range": this.continuous,
|
|
1466
|
-
"mdc-slider--discreet": !this.continuous,
|
|
1467
|
-
"mdc-slider--disabled": this.disabled || this.readonly
|
|
1468
|
-
};
|
|
1469
|
-
|
|
1470
|
-
inputElem = html`
|
|
1471
|
-
<span id="wrapper">
|
|
1472
|
-
${this.label ? html`<label for="component" class="${this.disabled ? "mdc-switch--disabled" : ""}">${this.label}</label>` : ``}
|
|
1473
|
-
<div id="component" class="${classMap(classes)}" @MDCSlider:change="${(ev:CustomEvent<MDCSliderChangeEventDetail>) => this.onValueChange(undefined, ev.detail.value)}">
|
|
1474
|
-
<input id="elem" class="mdc-slider__input" type="range" min="${ifDefined(valMinMax[1])}" max="${ifDefined(valMinMax[2])}" value="${valMinMax[0] || valMinMax[1] || 0}" name="slider" step="${this.step || 1}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" aria-label="${ifDefined(this.label)}" />
|
|
1475
|
-
<div class="mdc-slider__track">
|
|
1476
|
-
<div class="mdc-slider__track--inactive"></div>
|
|
1477
|
-
<div class="mdc-slider__track--active">
|
|
1478
|
-
<div class="mdc-slider__track--active_fill"></div>
|
|
1479
|
-
</div>
|
|
1480
|
-
</div>
|
|
1481
|
-
<div class="mdc-slider__thumb">
|
|
1482
|
-
${!this.continuous ? html`<div class="mdc-slider__value-indicator-container" aria-hidden="true">
|
|
1483
|
-
<div class="mdc-slider__value-indicator">
|
|
1484
|
-
<span class="mdc-slider__value-indicator-text">
|
|
1485
|
-
50
|
|
1486
|
-
</span>
|
|
1487
|
-
</div>
|
|
1488
|
-
</div>` : ``}
|
|
1489
|
-
<div class="mdc-slider__thumb-knob"></div>
|
|
1490
|
-
</div>
|
|
1491
|
-
</div>
|
|
1492
|
-
${inputElem ? html`<div style="min-width: 70px; width: 70px;">${inputElem}</div>` : ``}
|
|
1493
|
-
</span>
|
|
1494
|
-
`;
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
return inputElem;
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
return html`<span>INPUT TYPE NOT IMPLEMENTED</span>`;
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
protected _getFormat(): ValueFormat | undefined {
|
|
1506
|
-
if (this.format) {
|
|
1507
|
-
return this.format;
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
update(_changedProperties: PropertyValues) {
|
|
1512
|
-
if (_changedProperties.has('autoValidate') && this._mdcComponent) {
|
|
1513
|
-
const comp = this._mdcComponent as any;
|
|
1514
|
-
if (comp.foundation && comp.foundation.setValidateOnValueChange) {
|
|
1515
|
-
comp.foundation.setValidateOnValueChange(this.autoValidate);
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
super.update(_changedProperties);
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
firstUpdated(_changedProperties: PropertyValues) {
|
|
1523
|
-
super.firstUpdated(_changedProperties);
|
|
1524
|
-
|
|
1525
|
-
if (this.autoValidate) {
|
|
1526
|
-
this.reportValidity();
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
protected updated(_changedProperties: PropertyValues): void {
|
|
1531
|
-
super.updated(_changedProperties);
|
|
1532
|
-
|
|
1533
|
-
if (_changedProperties.has("type")) {
|
|
1534
|
-
const component = this.shadowRoot!.getElementById("component");
|
|
1535
|
-
if (this._mdcComponent) {
|
|
1536
|
-
this._mdcComponent.destroy();
|
|
1537
|
-
this._mdcComponent = undefined;
|
|
1538
|
-
}
|
|
1539
|
-
if (this._mdcComponent2) {
|
|
1540
|
-
this._mdcComponent2.destroy();
|
|
1541
|
-
this._mdcComponent2 = undefined;
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
|
-
if (component && this.type) {
|
|
1545
|
-
switch (this.type) {
|
|
1546
|
-
case InputType.LIST:
|
|
1547
|
-
const mdcList = new MDCList(component);
|
|
1548
|
-
this._mdcComponent = mdcList;
|
|
1549
|
-
mdcList.selectedIndex = this._selectedIndex;
|
|
1550
|
-
break;
|
|
1551
|
-
case InputType.SELECT:
|
|
1552
|
-
const mdcSelect = new MDCSelect(component);
|
|
1553
|
-
this._mdcComponent = mdcSelect;
|
|
1554
|
-
|
|
1555
|
-
const hasValue = (this.value !== null && this.value !== undefined);
|
|
1556
|
-
if (!hasValue) {
|
|
1557
|
-
mdcSelect.selectedIndex = -1; // Without this first option will be shown as selected
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
if (this.multiple) {
|
|
1561
|
-
// To make multiple select work then override the adapter getSelectedIndex
|
|
1562
|
-
(this._mdcComponent as any).foundation.adapter.getSelectedIndex = () => {
|
|
1563
|
-
// Return first item index
|
|
1564
|
-
if (!Array.isArray(this.value) || (this.value as []).length === 0) {
|
|
1565
|
-
return -1;
|
|
1566
|
-
}
|
|
1567
|
-
const firstSelected = (this.value as any[])[0];
|
|
1568
|
-
const items = (this._mdcComponent as any).foundation.adapter.getMenuItemValues();
|
|
1569
|
-
return items.indexOf(firstSelected);
|
|
1570
|
-
};
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
mdcSelect.useDefaultValidation = !this.multiple;
|
|
1574
|
-
mdcSelect.valid = !this.required || (!this.multiple && mdcSelect.valid) || (this.multiple && Array.isArray(this.value) && (this.value as []).length > 0);
|
|
1575
|
-
|
|
1576
|
-
const selectedText = this.getSelectedTextValue();
|
|
1577
|
-
(this._mdcComponent as any).foundation.adapter.setSelectedText(selectedText);
|
|
1578
|
-
(this._mdcComponent as any).foundation.adapter.floatLabel(!!selectedText);
|
|
1579
|
-
|
|
1580
|
-
// Set width of fixed select menu to match the component width
|
|
1581
|
-
// Using an observer to prevent forced reflow / DOM measurements; prevents blocking the thread
|
|
1582
|
-
if(!this._menuObserver) {
|
|
1583
|
-
this._menuObserver = new IntersectionObserver((entries, observer) => {
|
|
1584
|
-
if((entries[0].target as HTMLElement).style.minWidth != (entries[0].target.parentElement?.clientWidth + "px")) {
|
|
1585
|
-
(entries[0].target as HTMLElement).style.minWidth = entries[0].target.parentElement?.clientWidth + "px";
|
|
1586
|
-
}
|
|
1587
|
-
})
|
|
1588
|
-
this._menuObserver.observe(this.shadowRoot!.getElementById("mdc-select-menu")!);
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
// This overrides the standard mdc menu body click capture handler as it doesn't work with webcomponents
|
|
1592
|
-
const searchable: boolean = (this.searchProvider !== undefined);
|
|
1593
|
-
const multi: boolean = this.multiple;
|
|
1594
|
-
(mdcSelect as any).menu.menuSurface_.foundation.handleBodyClick = function (evt: MouseEvent) {
|
|
1595
|
-
const el = evt.composedPath()[0]; // Use composed path not evt target to work with webcomponents
|
|
1596
|
-
if (this.adapter.isElementInContainer(el)) {
|
|
1597
|
-
if(!searchable) {
|
|
1598
|
-
return; // Normal select menu closes automatically, so abort
|
|
1599
|
-
}
|
|
1600
|
-
// if searchable, we manually close the menu when clicking a list item.
|
|
1601
|
-
// However, if something else than a list item (for example the search field) is clicked, it should not close, so abort.
|
|
1602
|
-
else if (el instanceof Element && !el.className.includes('mdc-list-item')) {
|
|
1603
|
-
return;
|
|
1604
|
-
}
|
|
1605
|
-
else if (multi) {
|
|
1606
|
-
return;
|
|
1607
|
-
}
|
|
1608
|
-
}
|
|
1609
|
-
(mdcSelect as any).menu.menuSurface_.close();
|
|
1610
|
-
};
|
|
1611
|
-
|
|
1612
|
-
break;
|
|
1613
|
-
case InputType.RADIO:
|
|
1614
|
-
case InputType.CHECKBOX_LIST:
|
|
1615
|
-
case InputType.COLOUR:
|
|
1616
|
-
break;
|
|
1617
|
-
case InputType.BUTTON:
|
|
1618
|
-
case InputType.BUTTON_MOMENTARY:
|
|
1619
|
-
const isIconButton = !this.action && !this.label;
|
|
1620
|
-
const ripple = new MDCRipple(component);
|
|
1621
|
-
if (isIconButton) {
|
|
1622
|
-
ripple.unbounded = true;
|
|
1623
|
-
}
|
|
1624
|
-
this._mdcComponent = ripple;
|
|
1625
|
-
break;
|
|
1626
|
-
case InputType.BUTTON_TOGGLE:
|
|
1627
|
-
this._mdcComponent = new MDCIconButtonToggle(component);
|
|
1628
|
-
break;
|
|
1629
|
-
case InputType.CHECKBOX:
|
|
1630
|
-
this._mdcComponent = new MDCCheckbox(component);
|
|
1631
|
-
const field = this.shadowRoot!.getElementById("field");
|
|
1632
|
-
if (field) {
|
|
1633
|
-
const mdcField = new MDCFormField(field);
|
|
1634
|
-
mdcField.input = this._mdcComponent as unknown as MDCFormFieldInput;
|
|
1635
|
-
this._mdcComponent2 = mdcField;
|
|
1636
|
-
}
|
|
1637
|
-
break;
|
|
1638
|
-
case InputType.SWITCH:
|
|
1639
|
-
this._mdcComponent = new MDCSwitch(component);
|
|
1640
|
-
break;
|
|
1641
|
-
case InputType.RANGE:
|
|
1642
|
-
this._mdcComponent = new MDCSlider(component);
|
|
1643
|
-
const numberComponent = this.shadowRoot!.getElementById("number");
|
|
1644
|
-
if (numberComponent) {
|
|
1645
|
-
const numberField = new MDCTextField(numberComponent);
|
|
1646
|
-
numberField.useNativeValidation = false;
|
|
1647
|
-
this._mdcComponent2 = numberField;
|
|
1648
|
-
}
|
|
1649
|
-
break;
|
|
1650
|
-
default:
|
|
1651
|
-
const textField = new MDCTextField(component);
|
|
1652
|
-
textField.useNativeValidation = false;
|
|
1653
|
-
this._mdcComponent = textField;
|
|
1654
|
-
break;
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
if (this._mdcComponent && this.focused && typeof((this._mdcComponent as any).focus) === "function") {
|
|
1658
|
-
(this._mdcComponent as any).focus();
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
} else {
|
|
1662
|
-
// some components need to be kept in sync with the DOM
|
|
1663
|
-
if (this.type === InputType.SELECT && this._mdcComponent) {
|
|
1664
|
-
if (_changedProperties.has("options")) {
|
|
1665
|
-
(this._mdcComponent as MDCSelect).layoutOptions(); // has big impact on performance when the MDCSelect list is large.
|
|
1666
|
-
}
|
|
1667
|
-
(this._mdcComponent as MDCSelect).disabled = !!(this.disabled || this.readonly);
|
|
1668
|
-
(this._mdcComponent as MDCSelect).useDefaultValidation = !this.multiple;
|
|
1669
|
-
(this._mdcComponent as MDCSelect).valid = !this.required || (!this.multiple && (this._mdcComponent as MDCSelect).valid) || (this.multiple && Array.isArray(this.value) && (this.value as []).length > 0);
|
|
1670
|
-
const selectedText = this.getSelectedTextValue();
|
|
1671
|
-
(this._mdcComponent as any).foundation.adapter.setSelectedText(selectedText);
|
|
1672
|
-
(this._mdcComponent as any).foundation.adapter.floatLabel(!!selectedText);
|
|
1673
|
-
} else if (this.type === InputType.RANGE && this._mdcComponent) {
|
|
1674
|
-
const slider = this._mdcComponent as MDCSlider;
|
|
1675
|
-
slider.setDisabled(this.disabled || this.readonly);
|
|
1676
|
-
// slider.getDefaultFoundation(). getDefaultFoundation()..getMax() = this.min;
|
|
1677
|
-
// slider.max = this.max;
|
|
1678
|
-
slider.setValue(this.value);
|
|
1679
|
-
} else if (this.type === InputType.SWITCH && this._mdcComponent) {
|
|
1680
|
-
const swtch = this._mdcComponent as MDCSwitch;
|
|
1681
|
-
swtch.checked = this.value;
|
|
1682
|
-
} else if (this.type === InputType.CHECKBOX && this._mdcComponent) {
|
|
1683
|
-
const checkbox = this._mdcComponent as MDCCheckbox;
|
|
1684
|
-
checkbox.checked = !!this.value;
|
|
1685
|
-
checkbox.disabled = !!(this.disabled || this.readonly);
|
|
1686
|
-
}
|
|
1687
|
-
|
|
1688
|
-
if (this._mdcComponent) {
|
|
1689
|
-
(this._mdcComponent as any).required = !!this.required;
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
|
-
if(_changedProperties.has("label")) {
|
|
1694
|
-
(this._mdcComponent as any)?.layout?.(); // Adjusts the dimensions and positions for all sub-elements.
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
if (this.autoValidate) {
|
|
1698
|
-
this.reportValidity();
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
protected renderOutlined(labelTemplate: TemplateResult | undefined) {
|
|
1703
|
-
return html`
|
|
1704
|
-
<span class="mdc-notched-outline">
|
|
1705
|
-
<span class="mdc-notched-outline__leading"></span>
|
|
1706
|
-
${labelTemplate ? html`
|
|
1707
|
-
<span class="mdc-notched-outline__notch">
|
|
1708
|
-
${labelTemplate}
|
|
1709
|
-
</span>
|
|
1710
|
-
` : ``}
|
|
1711
|
-
<span class="mdc-notched-outline__trailing"></span>
|
|
1712
|
-
</span>
|
|
1713
|
-
`;
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
public setCustomValidity(msg: string | undefined) {
|
|
1717
|
-
this.errorMessage = msg;
|
|
1718
|
-
const elem = this.shadowRoot!.getElementById("elem") as HTMLElement;
|
|
1719
|
-
if (elem && (elem as any).setCustomValidity) {
|
|
1720
|
-
(elem as any).setCustomValidity(msg ?? "");
|
|
1721
|
-
}
|
|
1722
|
-
this.reportValidity();
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
public checkValidity(): boolean {
|
|
1726
|
-
const elem = this.shadowRoot!.getElementById("elem") as any;
|
|
1727
|
-
let valid = true;
|
|
1728
|
-
if (elem && elem.validity) {
|
|
1729
|
-
const nativeValidity = elem.validity as ValidityState;
|
|
1730
|
-
valid = nativeValidity.valid;
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
if (valid && (this.type === InputType.JSON || this.type === InputType.JSON_OBJECT)) {
|
|
1734
|
-
// JSON needs special validation - if no text value but this.value then parsing failed
|
|
1735
|
-
if (this.value !== undefined && this.value !== null && (this._mdcComponent as MDCTextField).value === "") {
|
|
1736
|
-
valid = false;
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
return valid;
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
public reportValidity(): boolean {
|
|
1744
|
-
const isValid = this.checkValidity();
|
|
1745
|
-
this.isUiValid = isValid;
|
|
1746
|
-
|
|
1747
|
-
if (this._mdcComponent) {
|
|
1748
|
-
(this._mdcComponent as any).valid = isValid;
|
|
1749
|
-
}
|
|
1750
|
-
|
|
1751
|
-
return isValid;
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
protected onValueChange(elem: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | undefined, newValue: any | undefined, enterPressed?: boolean) {
|
|
1755
|
-
let previousValue = this.value;
|
|
1756
|
-
let errorMsg: string | undefined;
|
|
1757
|
-
|
|
1758
|
-
if (newValue === "undefined") {
|
|
1759
|
-
previousValue = null;
|
|
1760
|
-
newValue = undefined;
|
|
1761
|
-
}
|
|
1762
|
-
|
|
1763
|
-
if (newValue === "null") {
|
|
1764
|
-
previousValue = undefined;
|
|
1765
|
-
newValue = null;
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
|
-
if (typeof(newValue) === "string") {
|
|
1769
|
-
switch (this.type) {
|
|
1770
|
-
case InputType.CHECKBOX:
|
|
1771
|
-
case InputType.SWITCH:
|
|
1772
|
-
newValue = newValue === "on";
|
|
1773
|
-
break;
|
|
1774
|
-
case InputType.JSON:
|
|
1775
|
-
case InputType.JSON_OBJECT:
|
|
1776
|
-
case InputType.NUMBER:
|
|
1777
|
-
case InputType.RANGE:
|
|
1778
|
-
if (newValue === "") {
|
|
1779
|
-
newValue = null;
|
|
1780
|
-
} else {
|
|
1781
|
-
try {
|
|
1782
|
-
newValue = JSON.parse(newValue);
|
|
1783
|
-
if (this.type === InputType.JSON_OBJECT && (typeof newValue !== 'object' || Array.isArray(newValue))) {
|
|
1784
|
-
newValue = this.value;
|
|
1785
|
-
errorMsg = i18next.t("validation.invalidJSON");
|
|
1786
|
-
}
|
|
1787
|
-
} catch (e) {
|
|
1788
|
-
newValue = this.value;
|
|
1789
|
-
errorMsg = this.type === InputType.JSON || this.type == InputType.JSON_OBJECT ? i18next.t("validation.invalidJSON") : i18next.t("validation.invalidNumber");
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
break;
|
|
1793
|
-
case InputType.DATETIME:
|
|
1794
|
-
if (newValue === "") {
|
|
1795
|
-
newValue = null;
|
|
1796
|
-
} else {
|
|
1797
|
-
try {
|
|
1798
|
-
newValue = Date.parse(newValue);
|
|
1799
|
-
} catch (e) {
|
|
1800
|
-
newValue = this.value;
|
|
1801
|
-
errorMsg = i18next.t("validation.invalidDate");
|
|
1802
|
-
}
|
|
1803
|
-
}
|
|
1804
|
-
break;
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
this.value = newValue;
|
|
1808
|
-
this.setCustomValidity(errorMsg);
|
|
1809
|
-
this.reportValidity();
|
|
1810
|
-
|
|
1811
|
-
if (this.type !== InputType.CHECKBOX_LIST && newValue !== previousValue) {
|
|
1812
|
-
if (this.type === InputType.RANGE) {
|
|
1813
|
-
(this._mdcComponent as MDCSlider).setValue(newValue);
|
|
1814
|
-
if (this._mdcComponent2) {
|
|
1815
|
-
(this._mdcComponent2 as MDCTextField).value = newValue;
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
this.dispatchEvent(new OrInputChangedEvent(this.value, previousValue, enterPressed));
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
// Reset search if value has been selected
|
|
1822
|
-
if(this.searchProvider != undefined && this.type === InputType.SELECT) {
|
|
1823
|
-
const searchableElement = this.shadowRoot?.getElementById('select-searchable')?.children[1];
|
|
1824
|
-
if(searchableElement) {
|
|
1825
|
-
this.searchableValue = undefined;
|
|
1826
|
-
(searchableElement as HTMLInputElement).value = "";
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
|
|
1830
|
-
if (this.type === InputType.CHECKBOX_LIST && !Util.objectsEqual(newValue, previousValue, true)) {
|
|
1831
|
-
this.dispatchEvent(new OrInputChangedEvent(newValue, previousValue, enterPressed));
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
|
|
1835
|
-
public get valid(): boolean {
|
|
1836
|
-
const elem = this.shadowRoot!.getElementById("elem") as any;
|
|
1837
|
-
if (elem && elem.checkValidity) {
|
|
1838
|
-
return elem.checkValidity();
|
|
1839
|
-
}
|
|
1840
|
-
return true;
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
public get currentValue(): any {
|
|
1844
|
-
const elem = this.shadowRoot!.getElementById("elem") as any;
|
|
1845
|
-
if (elem && elem.value) {
|
|
1846
|
-
return elem.value;
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
|
|
1850
|
-
protected resolveOptions(options: any[] | undefined): [any, string][] | undefined {
|
|
1851
|
-
let resolved: [any, string][] | undefined;
|
|
1852
|
-
|
|
1853
|
-
if (options && options.length > 0) {
|
|
1854
|
-
resolved = options.map(opt => {
|
|
1855
|
-
if (Array.isArray(opt)) {
|
|
1856
|
-
return opt as [any, string];
|
|
1857
|
-
} else {
|
|
1858
|
-
const optStr = "" + opt;
|
|
1859
|
-
return [opt, i18next.t(optStr, {defaultValue: Util.camelCaseToSentenceCase(optStr)})]
|
|
1860
|
-
}
|
|
1861
|
-
});
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
return resolved;
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
protected getSelectedTextValue(options?: [string, string][] | undefined): string {
|
|
1868
|
-
const value = this.value;
|
|
1869
|
-
const values = Array.isArray(value) ? value as string[] : value != null ? [value as string] : undefined;
|
|
1870
|
-
if (!values) {
|
|
1871
|
-
return "";
|
|
1872
|
-
}
|
|
1873
|
-
const opts = options || this.resolveOptions(this.options);
|
|
1874
|
-
return !opts || !values ? "" : values.map(v => opts.find(([optValue, optDisplay], index) => v === optValue)).map((opt) => opt ? opt[1] : "").join(", ");
|
|
1875
|
-
}
|
|
1876
|
-
}
|