@limetech/lime-elements 33.12.1-next.5 → 33.13.0-next.2
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/dist/cjs/limel-flatpickr-adapter_2.cjs.entry.js +333 -346
- package/dist/cjs/limel-select.cjs.entry.js +1 -1
- package/dist/cjs/limel-slider.cjs.entry.js +1 -1
- package/dist/collection/components/input-field/input-field.css +5 -2
- package/dist/collection/components/input-field/input-field.js +338 -351
- package/dist/collection/components/select/select.css +2 -0
- package/dist/collection/components/slider/slider.css +0 -13
- package/dist/collection/style/colors.scss +12 -0
- package/dist/esm/limel-flatpickr-adapter_2.entry.js +333 -346
- package/dist/esm/limel-select.entry.js +1 -1
- package/dist/esm/limel-slider.entry.js +1 -1
- package/dist/lime-elements/lime-elements.css +1 -1
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/{p-03f07f46.entry.js → p-24c128ec.entry.js} +3 -3
- package/dist/lime-elements/{p-af21dda0.entry.js → p-5780d004.entry.js} +2 -2
- package/dist/lime-elements/{p-63605145.entry.js → p-af7c5b11.entry.js} +4 -4
- package/dist/lime-elements/style/colors.scss +12 -0
- package/dist/types/components/input-field/input-field.d.ts +2 -2
- package/dist/types/components/progress-flow/progress-flow.types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -81,6 +81,145 @@ export class InputField {
|
|
|
81
81
|
this.isModified = false;
|
|
82
82
|
this.showCompletions = false;
|
|
83
83
|
this.completionsList = [];
|
|
84
|
+
this.initialize = () => {
|
|
85
|
+
const element = this.limelInputField.shadowRoot.querySelector('.mdc-text-field');
|
|
86
|
+
if (!element) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.mdcTextField = new MDCTextField(element);
|
|
90
|
+
this.completionsList = [...this.completions].map((item) => {
|
|
91
|
+
return { text: item };
|
|
92
|
+
});
|
|
93
|
+
window.addEventListener('resize', this.layout, { passive: true });
|
|
94
|
+
this.limelInputField.addEventListener('focus', this.setFocus);
|
|
95
|
+
};
|
|
96
|
+
this.setFocus = () => {
|
|
97
|
+
this.mdcTextField.focus();
|
|
98
|
+
};
|
|
99
|
+
this.getContainerClassList = () => {
|
|
100
|
+
const classList = {
|
|
101
|
+
'mdc-text-field': true,
|
|
102
|
+
'mdc-text-field--outlined': true,
|
|
103
|
+
'mdc-text-field--invalid': this.isInvalid(),
|
|
104
|
+
'mdc-text-field--disabled': this.disabled || this.readonly,
|
|
105
|
+
'lime-text-field--readonly': this.readonly,
|
|
106
|
+
'mdc-text-field--required': this.required,
|
|
107
|
+
'mdc-text-field--with-trailing-icon': !!this.getTrailingIcon(),
|
|
108
|
+
};
|
|
109
|
+
if (this.type === 'textarea') {
|
|
110
|
+
classList['mdc-text-field--textarea'] = true;
|
|
111
|
+
classList['has-helper-line'] =
|
|
112
|
+
!!this.helperText || !!this.maxlength;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
classList['mdc-text-field--with-leading-icon'] = !!this.leadingIcon;
|
|
116
|
+
}
|
|
117
|
+
return classList;
|
|
118
|
+
};
|
|
119
|
+
this.renderInput = (properties) => {
|
|
120
|
+
if (this.type === 'textarea') {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const type = this.type === 'urlAsText' ? 'text' : this.type;
|
|
124
|
+
return (h("input", Object.assign({}, properties, { type: type, pattern: this.pattern, onWheel: this.handleWheel, onKeyDown: this.onKeyDown, value: this.value })));
|
|
125
|
+
};
|
|
126
|
+
this.renderTextarea = (properties) => {
|
|
127
|
+
if (this.type !== 'textarea') {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
return (h("span", { class: "mdc-text-field__resizer" },
|
|
131
|
+
h("textarea", Object.assign({}, properties), this.value)));
|
|
132
|
+
};
|
|
133
|
+
this.layout = () => {
|
|
134
|
+
var _a;
|
|
135
|
+
(_a = this.mdcTextField) === null || _a === void 0 ? void 0 : _a.layout();
|
|
136
|
+
};
|
|
137
|
+
this.getAdditionalProps = () => {
|
|
138
|
+
const props = {};
|
|
139
|
+
if (this.type === 'number') {
|
|
140
|
+
props.step = this.step;
|
|
141
|
+
}
|
|
142
|
+
if (this.type === 'number' && Number.isInteger(this.min)) {
|
|
143
|
+
props.min = this.min;
|
|
144
|
+
}
|
|
145
|
+
if (this.type === 'number' && Number.isInteger(this.max)) {
|
|
146
|
+
props.max = this.max;
|
|
147
|
+
}
|
|
148
|
+
if (this.minlength) {
|
|
149
|
+
props.minlength = this.minlength;
|
|
150
|
+
}
|
|
151
|
+
if (this.maxlength) {
|
|
152
|
+
props.maxlength = this.maxlength;
|
|
153
|
+
}
|
|
154
|
+
return props;
|
|
155
|
+
};
|
|
156
|
+
this.onFocus = () => {
|
|
157
|
+
this.isFocused = true;
|
|
158
|
+
this.showCompletions = true;
|
|
159
|
+
};
|
|
160
|
+
this.onBlur = () => {
|
|
161
|
+
this.isFocused = false;
|
|
162
|
+
this.isModified = true;
|
|
163
|
+
};
|
|
164
|
+
this.renderHelperLine = () => {
|
|
165
|
+
if (!this.maxlength && !this.hasHelperText()) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
return (h("div", { tabIndex: -1, class: "mdc-text-field-helper-line" },
|
|
169
|
+
this.renderHelperText(),
|
|
170
|
+
this.renderCharacterCounter()));
|
|
171
|
+
};
|
|
172
|
+
this.renderEmptyValueForReadonly = () => {
|
|
173
|
+
if (this.readonly && !this.value) {
|
|
174
|
+
return (h("span", { class: "lime-empty-value-for-readonly lime-looks-like-input-value" }, "\u2013"));
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
this.renderHelperText = () => {
|
|
178
|
+
if (!this.hasHelperText()) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const classList = {
|
|
182
|
+
'mdc-text-field-helper-text': true,
|
|
183
|
+
'mdc-text-field-helper-text--validation-msg': this.isInvalid(),
|
|
184
|
+
};
|
|
185
|
+
return (h("p", { class: classList, id: helperTextId }, this.helperText));
|
|
186
|
+
};
|
|
187
|
+
this.hasHelperText = () => {
|
|
188
|
+
return this.helperText !== null && this.helperText !== undefined;
|
|
189
|
+
};
|
|
190
|
+
this.renderCharacterCounter = () => {
|
|
191
|
+
if (!this.maxlength || this.type === 'number') {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const text = this.value || '';
|
|
195
|
+
const label = `${text.length} / ${this.maxlength}`;
|
|
196
|
+
return h("div", { class: "mdc-text-field-character-counter" }, label);
|
|
197
|
+
};
|
|
198
|
+
this.isInvalid = () => {
|
|
199
|
+
if (this.readonly) {
|
|
200
|
+
// A readonly field can never be invalid.
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
if (this.invalid) {
|
|
204
|
+
// `this.invalid` is set by the consumer. If the consumer explicitly
|
|
205
|
+
// told us to consider the field invalid, we consider it invalid
|
|
206
|
+
// regardless of what our internal validation thinks, and regardless
|
|
207
|
+
// of whether the field has been modified.
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
if (!this.isModified) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
const element = this.getInputElement();
|
|
214
|
+
return !(element && element.checkValidity());
|
|
215
|
+
};
|
|
216
|
+
this.getInputElement = () => {
|
|
217
|
+
let elementName = 'input';
|
|
218
|
+
if (this.type === 'textarea') {
|
|
219
|
+
elementName = 'textarea';
|
|
220
|
+
}
|
|
221
|
+
return this.limelInputField.shadowRoot.querySelector(elementName);
|
|
222
|
+
};
|
|
84
223
|
this.renderLeadingIcon = () => {
|
|
85
224
|
if (this.type === 'textarea') {
|
|
86
225
|
return;
|
|
@@ -104,25 +243,210 @@ export class InputField {
|
|
|
104
243
|
}
|
|
105
244
|
return html;
|
|
106
245
|
};
|
|
246
|
+
this.hasLink = () => {
|
|
247
|
+
return (this.showLink &&
|
|
248
|
+
['email', 'tel', 'url', 'urlAsText'].includes(this.type));
|
|
249
|
+
};
|
|
250
|
+
this.getLink = () => {
|
|
251
|
+
const props = { href: '' };
|
|
252
|
+
switch (this.type) {
|
|
253
|
+
case 'email':
|
|
254
|
+
props.href = `mailto:${this.value}`;
|
|
255
|
+
break;
|
|
256
|
+
case 'tel':
|
|
257
|
+
props.href = `tel:${this.value}`;
|
|
258
|
+
break;
|
|
259
|
+
default:
|
|
260
|
+
props.href = getHref(this.value);
|
|
261
|
+
props.target = getTarget(this.value);
|
|
262
|
+
}
|
|
263
|
+
return props;
|
|
264
|
+
};
|
|
265
|
+
this.renderLinkIcon = (linkProps, icon) => {
|
|
266
|
+
// If the trailing icon uses the class `mdc-text-field__icon--trailing`,
|
|
267
|
+
// MDC attaches a click handler to it, which apparently runs
|
|
268
|
+
// `preventDefault()` on the event. For links, we don't want that,
|
|
269
|
+
// so instead of `mdc-text-field__icon--trailing`, we use our own class
|
|
270
|
+
// `lime-trailing-icon-for-link`, which uses all the same styling. /Ads
|
|
271
|
+
return (h("a", Object.assign({}, linkProps, { class: "material-icons mdc-text-field__icon lime-trailing-icon-for-link", tabindex: this.disabled ? '-1' : '0', role: "button" }),
|
|
272
|
+
h("limel-icon", { name: icon })));
|
|
273
|
+
};
|
|
274
|
+
this.renderTrailingIcon = (icon) => {
|
|
275
|
+
const props = {
|
|
276
|
+
tabIndex: this.isInvalid() ? '-1' : '0',
|
|
277
|
+
};
|
|
278
|
+
if (!this.isInvalid()) {
|
|
279
|
+
props.onKeyPress = this.handleIconKeyPress;
|
|
280
|
+
props.onClick = this.handleIconClick;
|
|
281
|
+
props.role = 'button';
|
|
282
|
+
}
|
|
283
|
+
return (h("i", Object.assign({ class: "material-icons mdc-text-field__icon mdc-text-field__icon--trailing" }, props),
|
|
284
|
+
h("limel-icon", { name: icon })));
|
|
285
|
+
};
|
|
286
|
+
this.getTrailingIcon = () => {
|
|
287
|
+
if (this.isInvalid()) {
|
|
288
|
+
return 'high_importance';
|
|
289
|
+
}
|
|
290
|
+
if (this.trailingIcon) {
|
|
291
|
+
return this.trailingIcon;
|
|
292
|
+
}
|
|
293
|
+
if (this.showLink && this.type === 'email') {
|
|
294
|
+
return 'filled_message';
|
|
295
|
+
}
|
|
296
|
+
if (this.showLink && this.type === 'tel') {
|
|
297
|
+
return 'phone';
|
|
298
|
+
}
|
|
299
|
+
if (this.showLink &&
|
|
300
|
+
(this.type === 'url' || this.type === 'urlAsText')) {
|
|
301
|
+
return 'external_link';
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
this.renderFormattedNumber = () => {
|
|
305
|
+
if (this.type !== 'number') {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
let renderValue = this.value;
|
|
309
|
+
if (this.formatNumber && this.value) {
|
|
310
|
+
renderValue = new Intl.NumberFormat(navigator.language).format(Number(this.value));
|
|
311
|
+
}
|
|
312
|
+
return (h("span", { class: "lime-formatted-input lime-looks-like-input-value" }, renderValue));
|
|
313
|
+
};
|
|
314
|
+
/**
|
|
315
|
+
* Key handler for the input field
|
|
316
|
+
* Will change focus to the first/last item in the dropdown list to enable selection with the keyboard
|
|
317
|
+
*
|
|
318
|
+
* @param {KeyboardEvent} event event
|
|
319
|
+
* @returns {void}
|
|
320
|
+
*/
|
|
321
|
+
this.onKeyDown = (event) => {
|
|
322
|
+
this.showCompletions = true;
|
|
323
|
+
const isForwardTab = (event.key === TAB || event.keyCode === TAB_KEY_CODE) &&
|
|
324
|
+
!event.altKey &&
|
|
325
|
+
!event.metaKey &&
|
|
326
|
+
!event.shiftKey;
|
|
327
|
+
const isUp = event.key === ARROW_UP || event.keyCode === ARROW_UP_KEY_CODE;
|
|
328
|
+
const isDown = event.key === ARROW_DOWN || event.keyCode === ARROW_DOWN_KEY_CODE;
|
|
329
|
+
if (event.keyCode === TAB_KEY_CODE && event.shiftKey) {
|
|
330
|
+
this.showCompletions = false;
|
|
331
|
+
}
|
|
332
|
+
if (!isForwardTab && !isUp && !isDown) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const list = document.querySelector(` #${this.portalId} limel-list`);
|
|
336
|
+
if (!list) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
event.preventDefault();
|
|
340
|
+
if (isForwardTab || isDown) {
|
|
341
|
+
const listElement = list.shadowRoot.querySelector('.mdc-deprecated-list-item:first-child');
|
|
342
|
+
listElement.focus();
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (isUp) {
|
|
346
|
+
const listElement = list.shadowRoot.querySelector('.mdc-deprecated-list-item:last-child');
|
|
347
|
+
listElement.focus();
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
this.handleCompletionChange = (event) => {
|
|
351
|
+
event.stopPropagation();
|
|
352
|
+
if (!event.detail) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
this.showCompletions = false;
|
|
356
|
+
/*
|
|
357
|
+
This change event doesn't need to be debounced in itself, but we want
|
|
358
|
+
to make absolutely sure that an earlier change event that *has* been
|
|
359
|
+
debounced doesn't emit after this one. Therefore, we run this through
|
|
360
|
+
the same debounced emitter function. /Ads
|
|
361
|
+
*/
|
|
362
|
+
this.changeEmitter(event.detail.text);
|
|
363
|
+
};
|
|
364
|
+
this.renderAutocompleteList = () => {
|
|
365
|
+
if (this.type === 'textarea' || !this.completions.length) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
return this.renderDropdown();
|
|
369
|
+
};
|
|
370
|
+
this.renderPortal = (content = null) => {
|
|
371
|
+
const dropdownZIndex = getComputedStyle(this.limelInputField).getPropertyValue('--dropdown-z-index');
|
|
372
|
+
return (h("limel-portal", { visible: this.showCompletions, containerId: this.portalId, inheritParentWidth: true, containerStyle: { 'z-index': dropdownZIndex } },
|
|
373
|
+
h("limel-menu-surface", { open: this.showCompletions, allowClicksElement: this.limelInputField, style: {
|
|
374
|
+
'--menu-surface-width': '100%',
|
|
375
|
+
'max-height': 'inherit',
|
|
376
|
+
display: 'flex',
|
|
377
|
+
}, onDismiss: this.handleCloseMenu }, content)));
|
|
378
|
+
};
|
|
379
|
+
this.renderDropdown = () => {
|
|
380
|
+
const content = this.renderListResult();
|
|
381
|
+
return this.renderPortal(content);
|
|
382
|
+
};
|
|
383
|
+
this.renderListResult = () => {
|
|
384
|
+
const filteredCompletions = this.filterCompletions(this.value);
|
|
385
|
+
if (!filteredCompletions || filteredCompletions.length === 0) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
return (h("limel-list", { onChange: this.handleCompletionChange, onKeyDown: this.handleKeyDownInDropdown, type: "selectable", items: filteredCompletions }));
|
|
389
|
+
};
|
|
390
|
+
this.handleKeyDownInDropdown = (event) => {
|
|
391
|
+
const keyFound = [TAB, ESCAPE, ENTER].includes(event.key);
|
|
392
|
+
const keyCodeFound = [
|
|
393
|
+
TAB_KEY_CODE,
|
|
394
|
+
ESCAPE_KEY_CODE,
|
|
395
|
+
ENTER_KEY_CODE,
|
|
396
|
+
].includes(event.keyCode);
|
|
397
|
+
if (keyFound || keyCodeFound) {
|
|
398
|
+
this.setFocus();
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
this.handleCloseMenu = () => {
|
|
402
|
+
this.showCompletions = false;
|
|
403
|
+
};
|
|
107
404
|
this.filterCompletions = (filter) => {
|
|
108
405
|
if (!filter) {
|
|
109
406
|
return this.completionsList;
|
|
110
407
|
}
|
|
111
408
|
return this.completionsList.filter((completion) => completion.text.toLowerCase().indexOf(filter.toLowerCase()) > -1);
|
|
112
409
|
};
|
|
113
|
-
this.handleChange =
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
410
|
+
this.handleChange = (event) => {
|
|
411
|
+
event.stopPropagation();
|
|
412
|
+
let value = event.target.value;
|
|
413
|
+
if (this.type === 'number') {
|
|
414
|
+
if (!value && event.data) {
|
|
415
|
+
event.stopPropagation();
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (value) {
|
|
419
|
+
value = Number(value);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
this.changeEmitter(value);
|
|
423
|
+
};
|
|
424
|
+
this.changeEmitter = (value) => {
|
|
425
|
+
this.change.emit(value);
|
|
426
|
+
};
|
|
427
|
+
this.handleIconClick = () => {
|
|
428
|
+
if (!this.isInvalid()) {
|
|
429
|
+
this.action.emit();
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
this.handleIconKeyPress = (event) => {
|
|
433
|
+
const isEnter = event.key === ENTER || event.keyCode === ENTER_KEY_CODE;
|
|
434
|
+
const isSpace = event.key === SPACE || event.keyCode === SPACE_KEY_CODE;
|
|
435
|
+
if ((isSpace || isEnter) && !this.isInvalid()) {
|
|
436
|
+
this.action.emit();
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
this.handleWheel = () => {
|
|
440
|
+
// This empty event handler is here to circumvent a bug.
|
|
441
|
+
// In some browsers (Chrome for example), hovering the input with
|
|
442
|
+
// the input focused, and scrolling, will both change the value
|
|
443
|
+
// AND scroll the page. We would prefer to never change the value
|
|
444
|
+
// on scroll, instead always scrolling the page, but since we
|
|
445
|
+
// haven't found a way to do that, this is the next best thing, as
|
|
446
|
+
// it prevents the page from being scrolled, but only in the
|
|
447
|
+
// circumstances when the value is changed by the scrolling.
|
|
448
|
+
// Please test THOROUGHLY if you remove this event handler 😄
|
|
449
|
+
};
|
|
126
450
|
const debounceTimeout = 300;
|
|
127
451
|
this.changeEmitter = debounce(this.changeEmitter, debounceTimeout);
|
|
128
452
|
this.portalId = createRandomString();
|
|
@@ -133,18 +457,6 @@ export class InputField {
|
|
|
133
457
|
componentDidLoad() {
|
|
134
458
|
this.initialize();
|
|
135
459
|
}
|
|
136
|
-
initialize() {
|
|
137
|
-
const element = this.limelInputField.shadowRoot.querySelector('.mdc-text-field');
|
|
138
|
-
if (!element) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
this.mdcTextField = new MDCTextField(element);
|
|
142
|
-
this.completionsList = [...this.completions].map((item) => {
|
|
143
|
-
return { text: item };
|
|
144
|
-
});
|
|
145
|
-
window.addEventListener('resize', this.layout, { passive: true });
|
|
146
|
-
this.limelInputField.addEventListener('focus', this.setFocus);
|
|
147
|
-
}
|
|
148
460
|
disconnectedCallback() {
|
|
149
461
|
if (this.mdcTextField) {
|
|
150
462
|
this.mdcTextField.destroy();
|
|
@@ -184,18 +496,15 @@ export class InputField {
|
|
|
184
496
|
h("span", { class: labelClassList, id: labelId }, this.label)),
|
|
185
497
|
h("span", { class: "mdc-notched-outline__trailing" })),
|
|
186
498
|
this.renderLeadingIcon(),
|
|
187
|
-
this.renderFormattedNumber(),
|
|
188
499
|
this.renderEmptyValueForReadonly(),
|
|
189
500
|
this.renderInput(properties),
|
|
190
501
|
this.renderTextarea(properties),
|
|
502
|
+
this.renderFormattedNumber(),
|
|
191
503
|
this.renderTrailingLinkOrButton()),
|
|
192
504
|
this.renderHelperLine(),
|
|
193
505
|
this.renderAutocompleteList(),
|
|
194
506
|
];
|
|
195
507
|
}
|
|
196
|
-
setFocus() {
|
|
197
|
-
this.mdcTextField.focus();
|
|
198
|
-
}
|
|
199
508
|
valueWatcher(newValue) {
|
|
200
509
|
if (!this.mdcTextField) {
|
|
201
510
|
return;
|
|
@@ -204,328 +513,6 @@ export class InputField {
|
|
|
204
513
|
this.mdcTextField.value = newValue || '';
|
|
205
514
|
}
|
|
206
515
|
}
|
|
207
|
-
getContainerClassList() {
|
|
208
|
-
const classList = {
|
|
209
|
-
'mdc-text-field': true,
|
|
210
|
-
'mdc-text-field--outlined': true,
|
|
211
|
-
'mdc-text-field--invalid': this.isInvalid(),
|
|
212
|
-
'mdc-text-field--disabled': this.disabled || this.readonly,
|
|
213
|
-
'lime-text-field--readonly': this.readonly,
|
|
214
|
-
'mdc-text-field--required': this.required,
|
|
215
|
-
'mdc-text-field--with-trailing-icon': !!this.getTrailingIcon(),
|
|
216
|
-
};
|
|
217
|
-
if (this.type === 'textarea') {
|
|
218
|
-
classList['mdc-text-field--textarea'] = true;
|
|
219
|
-
classList['has-helper-line'] =
|
|
220
|
-
!!this.helperText || !!this.maxlength;
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
classList['mdc-text-field--with-leading-icon'] = !!this.leadingIcon;
|
|
224
|
-
}
|
|
225
|
-
return classList;
|
|
226
|
-
}
|
|
227
|
-
renderInput(properties) {
|
|
228
|
-
if (this.type === 'textarea') {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
const type = this.type === 'urlAsText' ? 'text' : this.type;
|
|
232
|
-
return (h("input", Object.assign({}, properties, { type: type, pattern: this.pattern, onWheel: this.handleWheel, onKeyDown: this.onKeyDown, value: this.value })));
|
|
233
|
-
}
|
|
234
|
-
renderTextarea(properties) {
|
|
235
|
-
if (this.type !== 'textarea') {
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
return (h("span", { class: "mdc-text-field__resizer" },
|
|
239
|
-
h("textarea", Object.assign({}, properties), this.value)));
|
|
240
|
-
}
|
|
241
|
-
layout() {
|
|
242
|
-
var _a;
|
|
243
|
-
(_a = this.mdcTextField) === null || _a === void 0 ? void 0 : _a.layout();
|
|
244
|
-
}
|
|
245
|
-
getAdditionalProps() {
|
|
246
|
-
const props = {};
|
|
247
|
-
if (this.type === 'number') {
|
|
248
|
-
props.step = this.step;
|
|
249
|
-
}
|
|
250
|
-
if (this.type === 'number' && Number.isInteger(this.min)) {
|
|
251
|
-
props.min = this.min;
|
|
252
|
-
}
|
|
253
|
-
if (this.type === 'number' && Number.isInteger(this.max)) {
|
|
254
|
-
props.max = this.max;
|
|
255
|
-
}
|
|
256
|
-
if (this.minlength) {
|
|
257
|
-
props.minlength = this.minlength;
|
|
258
|
-
}
|
|
259
|
-
if (this.maxlength) {
|
|
260
|
-
props.maxlength = this.maxlength;
|
|
261
|
-
}
|
|
262
|
-
return props;
|
|
263
|
-
}
|
|
264
|
-
onFocus() {
|
|
265
|
-
this.isFocused = true;
|
|
266
|
-
this.showCompletions = true;
|
|
267
|
-
}
|
|
268
|
-
onBlur() {
|
|
269
|
-
this.isFocused = false;
|
|
270
|
-
this.isModified = true;
|
|
271
|
-
}
|
|
272
|
-
renderHelperLine() {
|
|
273
|
-
if (!this.maxlength && !this.hasHelperText()) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
return (h("div", { tabIndex: -1, class: "mdc-text-field-helper-line" },
|
|
277
|
-
this.renderHelperText(),
|
|
278
|
-
this.renderCharacterCounter()));
|
|
279
|
-
}
|
|
280
|
-
renderEmptyValueForReadonly() {
|
|
281
|
-
if (this.readonly && !this.value) {
|
|
282
|
-
return (h("span", { class: "lime-empty-value-for-readonly lime-looks-like-input-value" }, "\u2013"));
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
renderHelperText() {
|
|
286
|
-
if (!this.hasHelperText()) {
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
const classList = {
|
|
290
|
-
'mdc-text-field-helper-text': true,
|
|
291
|
-
'mdc-text-field-helper-text--validation-msg': this.isInvalid(),
|
|
292
|
-
};
|
|
293
|
-
return (h("p", { class: classList, id: helperTextId }, this.helperText));
|
|
294
|
-
}
|
|
295
|
-
hasHelperText() {
|
|
296
|
-
return this.helperText !== null && this.helperText !== undefined;
|
|
297
|
-
}
|
|
298
|
-
renderCharacterCounter() {
|
|
299
|
-
if (!this.maxlength || this.type === 'number') {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
const text = this.value || '';
|
|
303
|
-
const label = `${text.length} / ${this.maxlength}`;
|
|
304
|
-
return h("div", { class: "mdc-text-field-character-counter" }, label);
|
|
305
|
-
}
|
|
306
|
-
isInvalid() {
|
|
307
|
-
if (this.readonly) {
|
|
308
|
-
// A readonly field can never be invalid.
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
311
|
-
if (this.invalid) {
|
|
312
|
-
// `this.invalid` is set by the consumer. If the consumer explicitly
|
|
313
|
-
// told us to consider the field invalid, we consider it invalid
|
|
314
|
-
// regardless of what our internal validation thinks, and regardless
|
|
315
|
-
// of whether the field has been modified.
|
|
316
|
-
return true;
|
|
317
|
-
}
|
|
318
|
-
if (!this.isModified) {
|
|
319
|
-
return false;
|
|
320
|
-
}
|
|
321
|
-
const element = this.getInputElement();
|
|
322
|
-
return !(element && element.checkValidity());
|
|
323
|
-
}
|
|
324
|
-
getInputElement() {
|
|
325
|
-
let elementName = 'input';
|
|
326
|
-
if (this.type === 'textarea') {
|
|
327
|
-
elementName = 'textarea';
|
|
328
|
-
}
|
|
329
|
-
return this.limelInputField.shadowRoot.querySelector(elementName);
|
|
330
|
-
}
|
|
331
|
-
hasLink() {
|
|
332
|
-
return (this.showLink &&
|
|
333
|
-
['email', 'tel', 'url', 'urlAsText'].includes(this.type));
|
|
334
|
-
}
|
|
335
|
-
getLink() {
|
|
336
|
-
const props = { href: '' };
|
|
337
|
-
switch (this.type) {
|
|
338
|
-
case 'email':
|
|
339
|
-
props.href = `mailto:${this.value}`;
|
|
340
|
-
break;
|
|
341
|
-
case 'tel':
|
|
342
|
-
props.href = `tel:${this.value}`;
|
|
343
|
-
break;
|
|
344
|
-
default:
|
|
345
|
-
props.href = getHref(this.value);
|
|
346
|
-
props.target = getTarget(this.value);
|
|
347
|
-
}
|
|
348
|
-
return props;
|
|
349
|
-
}
|
|
350
|
-
renderLinkIcon(linkProps, icon) {
|
|
351
|
-
// If the trailing icon uses the class `mdc-text-field__icon--trailing`,
|
|
352
|
-
// MDC attaches a click handler to it, which apparently runs
|
|
353
|
-
// `preventDefault()` on the event. For links, we don't want that,
|
|
354
|
-
// so instead of `mdc-text-field__icon--trailing`, we use our own class
|
|
355
|
-
// `lime-trailing-icon-for-link`, which uses all the same styling. /Ads
|
|
356
|
-
return (h("a", Object.assign({}, linkProps, { class: "material-icons mdc-text-field__icon lime-trailing-icon-for-link", tabindex: this.disabled ? '-1' : '0', role: "button" }),
|
|
357
|
-
h("limel-icon", { name: icon })));
|
|
358
|
-
}
|
|
359
|
-
renderTrailingIcon(icon) {
|
|
360
|
-
const props = {
|
|
361
|
-
tabIndex: this.isInvalid() ? '-1' : '0',
|
|
362
|
-
};
|
|
363
|
-
if (!this.isInvalid()) {
|
|
364
|
-
props.onKeyPress = this.handleIconKeyPress;
|
|
365
|
-
props.onClick = this.handleIconClick;
|
|
366
|
-
props.role = 'button';
|
|
367
|
-
}
|
|
368
|
-
return (h("i", Object.assign({ class: "material-icons mdc-text-field__icon mdc-text-field__icon--trailing" }, props),
|
|
369
|
-
h("limel-icon", { name: icon })));
|
|
370
|
-
}
|
|
371
|
-
getTrailingIcon() {
|
|
372
|
-
if (this.isInvalid()) {
|
|
373
|
-
return 'high_importance';
|
|
374
|
-
}
|
|
375
|
-
if (this.trailingIcon) {
|
|
376
|
-
return this.trailingIcon;
|
|
377
|
-
}
|
|
378
|
-
if (this.showLink && this.type === 'email') {
|
|
379
|
-
return 'filled_message';
|
|
380
|
-
}
|
|
381
|
-
if (this.showLink && this.type === 'tel') {
|
|
382
|
-
return 'phone';
|
|
383
|
-
}
|
|
384
|
-
if (this.showLink &&
|
|
385
|
-
(this.type === 'url' || this.type === 'urlAsText')) {
|
|
386
|
-
return 'external_link';
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
renderFormattedNumber() {
|
|
390
|
-
if (this.type !== 'number' || !this.value) {
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
let renderValue = this.value;
|
|
394
|
-
if (this.formatNumber) {
|
|
395
|
-
renderValue = new Intl.NumberFormat(navigator.language).format(Number(this.value));
|
|
396
|
-
}
|
|
397
|
-
return (h("span", { class: "lime-formatted-input lime-looks-like-input-value" }, renderValue));
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Key handler for the input field
|
|
401
|
-
* Will change focus to the first/last item in the dropdown list to enable selection with the keyboard
|
|
402
|
-
*
|
|
403
|
-
* @param {KeyboardEvent} event event
|
|
404
|
-
* @returns {void}
|
|
405
|
-
*/
|
|
406
|
-
onKeyDown(event) {
|
|
407
|
-
this.showCompletions = true;
|
|
408
|
-
const isForwardTab = (event.key === TAB || event.keyCode === TAB_KEY_CODE) &&
|
|
409
|
-
!event.altKey &&
|
|
410
|
-
!event.metaKey &&
|
|
411
|
-
!event.shiftKey;
|
|
412
|
-
const isUp = event.key === ARROW_UP || event.keyCode === ARROW_UP_KEY_CODE;
|
|
413
|
-
const isDown = event.key === ARROW_DOWN || event.keyCode === ARROW_DOWN_KEY_CODE;
|
|
414
|
-
if (event.keyCode === TAB_KEY_CODE && event.shiftKey) {
|
|
415
|
-
this.showCompletions = false;
|
|
416
|
-
}
|
|
417
|
-
if (!isForwardTab && !isUp && !isDown) {
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
const list = document.querySelector(` #${this.portalId} limel-list`);
|
|
421
|
-
if (!list) {
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
event.preventDefault();
|
|
425
|
-
if (isForwardTab || isDown) {
|
|
426
|
-
const listElement = list.shadowRoot.querySelector('.mdc-deprecated-list-item:first-child');
|
|
427
|
-
listElement.focus();
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
if (isUp) {
|
|
431
|
-
const listElement = list.shadowRoot.querySelector('.mdc-deprecated-list-item:last-child');
|
|
432
|
-
listElement.focus();
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
handleCompletionChange(event) {
|
|
436
|
-
event.stopPropagation();
|
|
437
|
-
if (!event.detail) {
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
this.showCompletions = false;
|
|
441
|
-
/*
|
|
442
|
-
This change event doesn't need to be debounced in itself, but we want
|
|
443
|
-
to make absolutely sure that an earlier change event that *has* been
|
|
444
|
-
debounced doesn't emit after this one. Therefore, we run this through
|
|
445
|
-
the same debounced emitter function. /Ads
|
|
446
|
-
*/
|
|
447
|
-
this.changeEmitter(event.detail.text);
|
|
448
|
-
}
|
|
449
|
-
renderAutocompleteList() {
|
|
450
|
-
if (this.type === 'textarea' || !this.completions.length) {
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
return this.renderDropdown();
|
|
454
|
-
}
|
|
455
|
-
renderPortal(content = null) {
|
|
456
|
-
const dropdownZIndex = getComputedStyle(this.limelInputField).getPropertyValue('--dropdown-z-index');
|
|
457
|
-
return (h("limel-portal", { visible: this.showCompletions, containerId: this.portalId, inheritParentWidth: true, containerStyle: { 'z-index': dropdownZIndex } },
|
|
458
|
-
h("limel-menu-surface", { open: this.showCompletions, allowClicksElement: this.limelInputField, style: {
|
|
459
|
-
'--menu-surface-width': '100%',
|
|
460
|
-
'max-height': 'inherit',
|
|
461
|
-
display: 'flex',
|
|
462
|
-
}, onDismiss: this.handleCloseMenu }, content)));
|
|
463
|
-
}
|
|
464
|
-
renderDropdown() {
|
|
465
|
-
const content = this.renderListResult();
|
|
466
|
-
return this.renderPortal(content);
|
|
467
|
-
}
|
|
468
|
-
renderListResult() {
|
|
469
|
-
const filteredCompletions = this.filterCompletions(this.value);
|
|
470
|
-
if (!filteredCompletions || filteredCompletions.length === 0) {
|
|
471
|
-
return null;
|
|
472
|
-
}
|
|
473
|
-
return (h("limel-list", { onChange: this.handleCompletionChange, onKeyDown: this.handleKeyDownInDropdown, type: "selectable", items: filteredCompletions }));
|
|
474
|
-
}
|
|
475
|
-
handleKeyDownInDropdown(event) {
|
|
476
|
-
const keyFound = [TAB, ESCAPE, ENTER].includes(event.key);
|
|
477
|
-
const keyCodeFound = [
|
|
478
|
-
TAB_KEY_CODE,
|
|
479
|
-
ESCAPE_KEY_CODE,
|
|
480
|
-
ENTER_KEY_CODE,
|
|
481
|
-
].includes(event.keyCode);
|
|
482
|
-
if (keyFound || keyCodeFound) {
|
|
483
|
-
this.setFocus();
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
handleCloseMenu() {
|
|
487
|
-
this.showCompletions = false;
|
|
488
|
-
}
|
|
489
|
-
handleChange(event) {
|
|
490
|
-
event.stopPropagation();
|
|
491
|
-
let value = event.target.value;
|
|
492
|
-
if (this.type === 'number') {
|
|
493
|
-
if (!value && event.data) {
|
|
494
|
-
event.stopPropagation();
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
if (value) {
|
|
498
|
-
value = Number(value);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
this.changeEmitter(value);
|
|
502
|
-
}
|
|
503
|
-
changeEmitter(value) {
|
|
504
|
-
this.change.emit(value);
|
|
505
|
-
}
|
|
506
|
-
handleIconClick() {
|
|
507
|
-
if (!this.isInvalid()) {
|
|
508
|
-
this.action.emit();
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
handleIconKeyPress(event) {
|
|
512
|
-
const isEnter = event.key === ENTER || event.keyCode === ENTER_KEY_CODE;
|
|
513
|
-
const isSpace = event.key === SPACE || event.keyCode === SPACE_KEY_CODE;
|
|
514
|
-
if ((isSpace || isEnter) && !this.isInvalid()) {
|
|
515
|
-
this.action.emit();
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
handleWheel() {
|
|
519
|
-
// This empty event handler is here to circumvent a bug.
|
|
520
|
-
// In some browsers (Chrome for example), hovering the input with
|
|
521
|
-
// the input focused, and scrolling, will both change the value
|
|
522
|
-
// AND scroll the page. We would prefer to never change the value
|
|
523
|
-
// on scroll, instead always scrolling the page, but since we
|
|
524
|
-
// haven't found a way to do that, this is the next best thing, as
|
|
525
|
-
// it prevents the page from being scrolled, but only in the
|
|
526
|
-
// circumstances when the value is changed by the scrolling.
|
|
527
|
-
// Please test THOROUGHLY if you remove this event handler 😄
|
|
528
|
-
}
|
|
529
516
|
static get is() { return "limel-input-field"; }
|
|
530
517
|
static get encapsulation() { return "shadow"; }
|
|
531
518
|
static get originalStyleUrls() { return {
|