@softpak/components 20.5.1 → 20.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/softpak-components-spx-alert.mjs +2 -2
- package/fesm2022/softpak-components-spx-alert.mjs.map +1 -1
- package/fesm2022/softpak-components-spx-inputs.mjs +188 -62
- package/fesm2022/softpak-components-spx-inputs.mjs.map +1 -1
- package/package.json +37 -37
- package/spx-inputs/index.d.ts +25 -12
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { signal, output, input, model, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { faCheck, faCircleInfo, faTriangleExclamation, faTimes } from '@fortawesome/free-solid-svg-icons';
|
|
3
4
|
import * as i1 from '@fortawesome/angular-fontawesome';
|
|
4
5
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
|
5
|
-
import { faCheck, faCircleInfo, faTriangleExclamation, faTimes } from '@fortawesome/free-solid-svg-icons';
|
|
6
|
-
import { SpxSeverityEnum } from '@softpak/components/spx-helpers';
|
|
7
6
|
import { IsSeverityPipe } from '@softpak/components/spx-pipes';
|
|
7
|
+
import { SpxSeverityEnum } from '@softpak/components/spx-helpers';
|
|
8
8
|
|
|
9
9
|
class SpxAlertComponent {
|
|
10
10
|
constructor() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"softpak-components-spx-alert.mjs","sources":["../../../../projects/softpak/components/spx-alert/spx-alert.component.ts","../../../../projects/softpak/components/spx-alert/spx-alert.component.html","../../../../projects/softpak/components/spx-alert/spx-alert.interface.ts","../../../../projects/softpak/components/spx-alert/softpak-components-spx-alert.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"softpak-components-spx-alert.mjs","sources":["../../../../projects/softpak/components/spx-alert/spx-alert.component.ts","../../../../projects/softpak/components/spx-alert/spx-alert.component.html","../../../../projects/softpak/components/spx-alert/spx-alert.interface.ts","../../../../projects/softpak/components/spx-alert/softpak-components-spx-alert.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, input, model, output, signal } from '@angular/core';\nimport { faCheck, faCircleInfo, faTimes, faTriangleExclamation } from '@fortawesome/free-solid-svg-icons';\n\nimport { FontAwesomeModule } from '@fortawesome/angular-fontawesome';\nimport { IsSeverityPipe } from \"@softpak/components/spx-pipes\";\nimport { SpxSeverityEnum } from '@softpak/components/spx-helpers';\n\n@Component({\n selector: 'spx-alert',\n imports: [\n FontAwesomeModule,\n IsSeverityPipe\n],\n templateUrl: './spx-alert.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n styleUrl: './spx-alert.component.scss',\n})\nexport class SpxAlertComponent {\n _autoCloseTimeout = signal<NodeJS.Timeout | null>(null);\n spxClose = output();\n readonly spxAutoclose = input<number>();\n readonly spxCloseable = input<boolean | undefined>(false);\n readonly spxHideTitle = input(false);\n readonly spxTitle = model<string>();\n readonly spxMarginTop = input(false);\n readonly spxSeverity = input<SpxSeverityEnum>();\n SpxSeverity = SpxSeverityEnum;\n faCheck = faCheck;\n faCircleInfo = faCircleInfo;\n faTriangleExclamation = faTriangleExclamation;\n faTimes = faTimes;\n\n componentDidLoad() {\n if (this.spxAutoclose()) {\n this.prepareAutoClose();\n }\n if (!this.spxTitle()) {\n this._assignDefaultTitle();\n }\n }\n\n private prepareAutoClose(): void {\n this._autoCloseTimeout.set(setTimeout(() => {\n this.onClose();\n this._autoCloseTimeout.set(null);\n }, this.spxAutoclose()));\n }\n\n private _assignDefaultTitle(): void {\n switch (this.spxSeverity()) {\n case SpxSeverityEnum.error:\n this.spxTitle.set('Error');\n break;\n case SpxSeverityEnum.info:\n this.spxTitle.set('Info');\n break;\n case SpxSeverityEnum.success:\n this.spxTitle.set('Notification');\n break;\n case SpxSeverityEnum.warning:\n this.spxTitle.set('Warning');\n break;\n }\n }\n\n onClose() {\n if (this.spxCloseable()) {\n this.spxClose.emit();\n }\n }\n}\n","<div class=\"flex items-center gap-3 border-t-4 rounded px-4 py-3 shadow-md\"\n [class.cursor-pointer]=\"this.spxCloseable()\"\n [class.bg-red-100]=\"this.spxSeverity() | isSeverity: SpxSeverity.error\"\n [class.border-red-500]=\"this.spxSeverity() | isSeverity: SpxSeverity.error\"\n [class.text-red-900]=\"this.spxSeverity() | isSeverity: SpxSeverity.error\"\n [class.bg-cyan-100]=\"this.spxSeverity() | isSeverity: SpxSeverity.info\"\n [class.border-cyan-500]=\"this.spxSeverity() | isSeverity: SpxSeverity.info\"\n [class.text-cyan-900]=\"this.spxSeverity() | isSeverity: SpxSeverity.info\"\n [class.bg-lime-100]=\"this.spxSeverity() | isSeverity: SpxSeverity.success\"\n [class.border-lime-500]=\"this.spxSeverity() | isSeverity: SpxSeverity.success\"\n [class.text-lime-900]=\"this.spxSeverity() | isSeverity: SpxSeverity.success\"\n [class.bg-amber-100]=\"this.spxSeverity() | isSeverity: SpxSeverity.warning\"\n [class.border-amber-500]=\"this.spxSeverity() | isSeverity: SpxSeverity.warning\"\n [class.text-amber-900]=\"this.spxSeverity() | isSeverity: SpxSeverity.warning\"\n [class.focus:ring-red-600]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.error)\"\n [class.hover:bg-red-200]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.error)\"\n [class.over:border-red-600]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.error)\"\n [class.focus:ring-cyan-600]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.info)\"\n [class.hover:bg-cyan-200]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.info)\"\n [class.over:border-cyan-600]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.info)\"\n [class.focus:ring-lime-600]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.success)\"\n [class.hover:bg-lime-200]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.success)\"\n [class.over:border-lime-600]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.success)\"\n [class.focus:ring-amber-600]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.warning)\"\n [class.hover:bg-amber-200]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.warning)\"\n [class.over:border-amber-600]=\"this.spxCloseable() && (this.spxSeverity() | isSeverity: SpxSeverity.warning)\"\n (click)=\"onClose()\">\n @if ((this.spxSeverity() | isSeverity: SpxSeverity.info)) {\n <fa-icon\n [icon]=\"faCircleInfo\" class=\"block text-xl text-cyan-600\"></fa-icon>\n }\n @if (this.spxSeverity() | isSeverity: SpxSeverity.error) {\n <fa-icon\n [icon]=\"faTriangleExclamation\" class=\"block text-xl text-red-600\"></fa-icon>\n }\n @if (this.spxSeverity() | isSeverity: SpxSeverity.success) {\n <fa-icon\n [icon]=\"faCheck\" class=\"block text-xl text-lime-600\"></fa-icon>\n }\n @if (this.spxSeverity() | isSeverity: SpxSeverity.warning) {\n <fa-icon\n [icon]=\"faTriangleExclamation\" class=\"block text-xl text-amber-600\"></fa-icon>\n }\n <div class=\"grow\">\n @if (this.spxTitle() && !this.spxHideTitle()) {\n <p class=\"font-bold\">{{this.spxTitle()}}</p>\n }\n <p class=\"text-sm\">\n <ng-content></ng-content>\n </p>\n </div>\n @if (this.spxCloseable()) {\n <fa-icon\n [icon]=\"faTimes\" class=\"block text-xl\"></fa-icon>\n }\n </div>","import { SpxSeverityEnum } from \"@softpak/components/spx-helpers\";\n\nexport class SpxAlertI {\n closeable?: boolean;\n id?: number;\n message?: string;\n severity?: SpxSeverityEnum;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, inject, computed, input, model, output, signal, HostListener, ChangeDetectionStrategy, Component, viewChild, EventEmitter, ViewChildren, Output } from '@angular/core';
|
|
2
|
+
import { Injectable, inject, computed, input, model, output, signal, HostListener, ChangeDetectionStrategy, Component, viewChild, EventEmitter, effect, ViewChildren, Output } from '@angular/core';
|
|
3
3
|
import { SpxButtonComponent } from '@softpak/components/spx-button';
|
|
4
4
|
import * as i1 from '@fortawesome/angular-fontawesome';
|
|
5
5
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
|
@@ -279,9 +279,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.2", ngImpor
|
|
|
279
279
|
// }
|
|
280
280
|
|
|
281
281
|
class SpxInputCycleComponent {
|
|
282
|
-
constructor(
|
|
283
|
-
this.
|
|
284
|
-
this.mappedReadonly = computed(() => this.spxReadonly() ? true : false, ...(ngDevMode ? [{ debugName: "mappedReadonly" }] : []));
|
|
282
|
+
constructor(cdr) {
|
|
283
|
+
this.cdr = cdr;
|
|
284
|
+
this.mappedReadonly = computed(() => (this.spxReadonly() ? true : false), ...(ngDevMode ? [{ debugName: "mappedReadonly" }] : []));
|
|
285
285
|
this.spxSpeedDial = input([], ...(ngDevMode ? [{ debugName: "spxSpeedDial" }] : []));
|
|
286
286
|
this.spxName = input(...(ngDevMode ? [undefined, { debugName: "spxName" }] : []));
|
|
287
287
|
this.spxAutofocus = input(false, ...(ngDevMode ? [{ debugName: "spxAutofocus" }] : []));
|
|
@@ -294,7 +294,7 @@ class SpxInputCycleComponent {
|
|
|
294
294
|
this.spxSeverity = computed(() => this.value()?.description, ...(ngDevMode ? [{ debugName: "spxSeverity" }] : []));
|
|
295
295
|
this.spxType = input(SpxInputTypeEnum.text, ...(ngDevMode ? [{ debugName: "spxType" }] : []));
|
|
296
296
|
this.spxWasInternalUpdate = input(false, ...(ngDevMode ? [{ debugName: "spxWasInternalUpdate" }] : []));
|
|
297
|
-
this.value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
|
|
297
|
+
this.value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : [])); // externe waarde via model()
|
|
298
298
|
this.spxElementId = input(...(ngDevMode ? [undefined, { debugName: "spxElementId" }] : []));
|
|
299
299
|
this.selectedInputService = inject(SelectedInputService);
|
|
300
300
|
this.spxIsFocused = signal(false, ...(ngDevMode ? [{ debugName: "spxIsFocused" }] : []));
|
|
@@ -302,93 +302,219 @@ class SpxInputCycleComponent {
|
|
|
302
302
|
this.severityError = SpxSeverityEnum.error;
|
|
303
303
|
this.severitySuccess = SpxSeverityEnum.success;
|
|
304
304
|
this.severityWarning = SpxSeverityEnum.warning;
|
|
305
|
+
this.isInternalUpdate = false;
|
|
306
|
+
this.cancelNextMouseUp = false;
|
|
307
|
+
// auto-advance/IME guards
|
|
308
|
+
this.composing = false;
|
|
309
|
+
this.advancing = false;
|
|
310
|
+
this.lastAdvanceAt = 0;
|
|
305
311
|
this.completeInput = new EventEmitter();
|
|
312
|
+
/** Externe wijzigingen via model() → sync naar interne state + DOM */
|
|
313
|
+
this._reactToValueChanges = effect(() => {
|
|
314
|
+
if (this.isInternalUpdate)
|
|
315
|
+
return; // eigen emits overslaan
|
|
316
|
+
this.updateIntervalValue(this.value() ?? null);
|
|
317
|
+
}, ...(ngDevMode ? [{ debugName: "_reactToValueChanges" }] : []));
|
|
306
318
|
}
|
|
307
319
|
ngOnInit() {
|
|
308
|
-
this.componentDidLoad();
|
|
309
320
|
const length = this.spxCycleConfig().length;
|
|
310
321
|
this.values = Array(length).fill('');
|
|
311
|
-
|
|
312
|
-
valuePairToValue(this.value()).split('').forEach((char, index) => {
|
|
313
|
-
if (this.values[index] !== undefined) {
|
|
314
|
-
this.values[index] = char;
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
}
|
|
322
|
+
this.updateIntervalValue(this.value() ?? null);
|
|
318
323
|
}
|
|
319
324
|
ngAfterViewInit() {
|
|
320
|
-
if (this.spxAutofocus())
|
|
325
|
+
if (this.spxAutofocus())
|
|
321
326
|
this.spxSetFocus();
|
|
327
|
+
this.applyValuesToDom();
|
|
328
|
+
}
|
|
329
|
+
// =========================
|
|
330
|
+
// Extern -> Intern & DOM
|
|
331
|
+
// =========================
|
|
332
|
+
updateIntervalValue(valuePair) {
|
|
333
|
+
const len = this.spxCycleConfig().length;
|
|
334
|
+
if (!this.values || this.values.length !== len) {
|
|
335
|
+
this.values = Array(len).fill('');
|
|
322
336
|
}
|
|
337
|
+
if (valuePair === null) {
|
|
338
|
+
// Externe reset → interne reset + DOM leegmaken
|
|
339
|
+
for (let i = 0; i < len; i++)
|
|
340
|
+
this.values[i] = '';
|
|
341
|
+
this.applyValuesToDom();
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const raw = valuePairToValue(valuePair);
|
|
345
|
+
const s = (raw ?? '').toString();
|
|
346
|
+
for (let i = 0; i < len; i++) {
|
|
347
|
+
const ch = s[i];
|
|
348
|
+
this.values[i] = ch ? (ch === '_' ? '' : ch) : '';
|
|
349
|
+
}
|
|
350
|
+
this.applyValuesToDom();
|
|
351
|
+
}
|
|
352
|
+
applyValuesToDom() {
|
|
353
|
+
queueMicrotask(() => {
|
|
354
|
+
const boxes = this.inputBoxes?.toArray() ?? [];
|
|
355
|
+
for (let pos = 0; pos < boxes.length; pos++) {
|
|
356
|
+
const el = boxes[pos]?.nativeElement;
|
|
357
|
+
if (!el)
|
|
358
|
+
continue;
|
|
359
|
+
const v = (this.values?.[pos] ?? '');
|
|
360
|
+
if (el.value !== v)
|
|
361
|
+
el.value = v;
|
|
362
|
+
}
|
|
363
|
+
});
|
|
323
364
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
componentDidLoad() {
|
|
329
|
-
// if (this.spxAutofocus()) {
|
|
330
|
-
// this.spxSetFocus();
|
|
331
|
-
// }
|
|
332
|
-
}
|
|
365
|
+
// =========================
|
|
366
|
+
// Intern -> Extern (emit)
|
|
367
|
+
// =========================
|
|
333
368
|
handleChange(event) {
|
|
369
|
+
this.isInternalUpdate = true;
|
|
334
370
|
this.value.set(event);
|
|
371
|
+
queueMicrotask(() => {
|
|
372
|
+
this.isInternalUpdate = false;
|
|
373
|
+
});
|
|
335
374
|
}
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
375
|
+
checkEmitCondition() {
|
|
376
|
+
const required = this.spxCycleConfig().requiredPositions;
|
|
377
|
+
const completed = this.values
|
|
378
|
+
.filter((_, i) => required[i] === true)
|
|
379
|
+
.every((val) => val !== '' && val !== null);
|
|
380
|
+
if (completed) {
|
|
381
|
+
const out = this.values.map((c) => (c === undefined || c === '' || c === null ? '_' : c)).join('').toUpperCase();
|
|
382
|
+
this.handleChange({ description: SpxSeverityEnum.warning, value: out });
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
this.handleChange(null); // incomplete → FormControl = null (interne values blijven staan)
|
|
340
386
|
}
|
|
341
387
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
388
|
+
// =========================
|
|
389
|
+
// Focus/select gedrag
|
|
390
|
+
// =========================
|
|
391
|
+
spxSetFocus() {
|
|
392
|
+
const pos = this.spxCycleConfig().defaultFocusPosition;
|
|
393
|
+
setTimeout(() => this.focusPos(pos));
|
|
394
|
+
}
|
|
395
|
+
onFocus(pos, _ev) {
|
|
396
|
+
const input = this.inputBoxes.toArray()[pos]?.nativeElement;
|
|
397
|
+
if (!input)
|
|
347
398
|
return;
|
|
399
|
+
setTimeout(() => input.select(), 0); // selecteer altijd alles bij focus
|
|
400
|
+
this.cancelNextMouseUp = true;
|
|
401
|
+
}
|
|
402
|
+
onMouseUp(ev) {
|
|
403
|
+
if (this.cancelNextMouseUp) {
|
|
404
|
+
ev.preventDefault(); // behoud selectie na muisklik
|
|
405
|
+
this.cancelNextMouseUp = false;
|
|
348
406
|
}
|
|
349
|
-
this.values[index] = char;
|
|
350
|
-
inputEl.value = char; // vervang inhoud expliciet
|
|
351
|
-
this.focusInput(this.nextIndex(index));
|
|
352
|
-
this.checkEmitCondition();
|
|
353
407
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
408
|
+
// =========================
|
|
409
|
+
// IME/compositie
|
|
410
|
+
// =========================
|
|
411
|
+
onCompositionStart() {
|
|
412
|
+
this.composing = true;
|
|
413
|
+
}
|
|
414
|
+
onCompositionEnd() {
|
|
415
|
+
this.composing = false;
|
|
416
|
+
}
|
|
417
|
+
// =========================
|
|
418
|
+
// Invoer
|
|
419
|
+
// =========================
|
|
420
|
+
onInput(pos, event) {
|
|
421
|
+
if (!this.values)
|
|
422
|
+
return;
|
|
423
|
+
const inputEl = event.target;
|
|
424
|
+
let v = inputEl.value ?? '';
|
|
425
|
+
// Eén teken per box
|
|
426
|
+
if (v.length > 1) {
|
|
427
|
+
v = v.charAt(0);
|
|
428
|
+
if (inputEl.value !== v)
|
|
429
|
+
inputEl.value = v;
|
|
368
430
|
}
|
|
431
|
+
this.values[pos] = v;
|
|
432
|
+
this.checkEmitCondition();
|
|
433
|
+
// Auto-advance guards
|
|
434
|
+
if (this.composing)
|
|
435
|
+
return; // niet tijdens IME
|
|
436
|
+
if (document.activeElement !== inputEl)
|
|
437
|
+
return; // race guard
|
|
438
|
+
if (v.length !== 1)
|
|
439
|
+
return; // alleen als er precies 1 teken staat
|
|
440
|
+
// throttle & re-entrancy
|
|
441
|
+
const now = Date.now();
|
|
442
|
+
if (this.advancing || now - this.lastAdvanceAt < 40)
|
|
443
|
+
return;
|
|
444
|
+
this.advancing = true;
|
|
445
|
+
setTimeout(() => {
|
|
446
|
+
// dubbel-check voor zekerheid
|
|
447
|
+
if (inputEl.value.length === 1 && document.activeElement === inputEl) {
|
|
448
|
+
const next = this.nextPos(pos);
|
|
449
|
+
this.focusPos(next);
|
|
450
|
+
this.lastAdvanceAt = Date.now();
|
|
451
|
+
}
|
|
452
|
+
this.advancing = false;
|
|
453
|
+
}, 0);
|
|
369
454
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const
|
|
373
|
-
if (
|
|
374
|
-
this.
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
455
|
+
// 1) Helper toevoegen
|
|
456
|
+
clearAllAndEmit() {
|
|
457
|
+
const len = this.spxCycleConfig().length;
|
|
458
|
+
if (!this.values || this.values.length !== len) {
|
|
459
|
+
this.values = Array(len).fill('');
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
for (let i = 0; i < len; i++)
|
|
463
|
+
this.values[i] = '';
|
|
464
|
+
}
|
|
465
|
+
this.applyValuesToDom(); // maak zichtbare inputs leeg
|
|
466
|
+
this.handleChange(null); // emit meteen null
|
|
467
|
+
// Focus terug naar startpositie uit config
|
|
468
|
+
const start = this.spxCycleConfig().defaultFocusPosition ?? 0;
|
|
469
|
+
this.focusPos(start);
|
|
470
|
+
}
|
|
471
|
+
// 2) onKeydown aanpassen
|
|
472
|
+
onKeydown(pos, event) {
|
|
473
|
+
const el = this.inputBoxes.toArray()[pos]?.nativeElement;
|
|
474
|
+
if (!el)
|
|
475
|
+
return;
|
|
476
|
+
// Replace-gedrag bij normale tekstinvoer mag blijven zoals je had
|
|
477
|
+
const isPrintable = event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
478
|
+
if (isPrintable && el.value.length >= 1 && el.selectionStart === el.selectionEnd) {
|
|
479
|
+
el.select();
|
|
480
|
+
}
|
|
481
|
+
// Nieuw: Backspace/Delete = ALLES leegmaken
|
|
482
|
+
if (event.key === 'Backspace' || event.key === 'Delete') {
|
|
483
|
+
event.preventDefault();
|
|
484
|
+
this.clearAllAndEmit();
|
|
485
|
+
return;
|
|
378
486
|
}
|
|
379
487
|
}
|
|
380
|
-
|
|
381
|
-
|
|
488
|
+
// =========================
|
|
489
|
+
// Navigatie (posities)
|
|
490
|
+
// =========================
|
|
491
|
+
nextPos(pos) {
|
|
492
|
+
const order = this.spxCycleConfig().focusOrder;
|
|
493
|
+
return (pos + 1) % order.length;
|
|
494
|
+
}
|
|
495
|
+
prevPos(pos) {
|
|
496
|
+
const order = this.spxCycleConfig().focusOrder;
|
|
497
|
+
return (pos - 1 + order.length) % order.length;
|
|
498
|
+
}
|
|
499
|
+
focusPos(pos) {
|
|
500
|
+
const el = this.inputBoxes.toArray()[pos]?.nativeElement;
|
|
501
|
+
if (!el)
|
|
502
|
+
return;
|
|
503
|
+
if (document.activeElement === el)
|
|
504
|
+
return; // al gefocust
|
|
505
|
+
el.focus();
|
|
506
|
+
if (el.value)
|
|
507
|
+
setTimeout(() => el.select(), 0);
|
|
382
508
|
}
|
|
383
509
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.2", ngImport: i0, type: SpxInputCycleComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
384
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.2", type: SpxInputCycleComponent, isStandalone: true, selector: "spx-input-cycle", inputs: { spxSpeedDial: { classPropertyName: "spxSpeedDial", publicName: "spxSpeedDial", isSignal: true, isRequired: false, transformFunction: null }, spxName: { classPropertyName: "spxName", publicName: "spxName", isSignal: true, isRequired: false, transformFunction: null }, spxAutofocus: { classPropertyName: "spxAutofocus", publicName: "spxAutofocus", isSignal: true, isRequired: false, transformFunction: null }, spxAutocomplete: { classPropertyName: "spxAutocomplete", publicName: "spxAutocomplete", isSignal: true, isRequired: false, transformFunction: null }, spxCycleConfig: { classPropertyName: "spxCycleConfig", publicName: "spxCycleConfig", isSignal: true, isRequired: true, transformFunction: null }, spxInputMode: { classPropertyName: "spxInputMode", publicName: "spxInputMode", isSignal: true, isRequired: false, transformFunction: null }, spxReadonly: { classPropertyName: "spxReadonly", publicName: "spxReadonly", isSignal: true, isRequired: false, transformFunction: null }, spxValidators: { classPropertyName: "spxValidators", publicName: "spxValidators", isSignal: true, isRequired: false, transformFunction: null }, spxCapitalize: { classPropertyName: "spxCapitalize", publicName: "spxCapitalize", isSignal: true, isRequired: false, transformFunction: null }, spxType: { classPropertyName: "spxType", publicName: "spxType", isSignal: true, isRequired: false, transformFunction: null }, spxWasInternalUpdate: { classPropertyName: "spxWasInternalUpdate", publicName: "spxWasInternalUpdate", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, spxElementId: { classPropertyName: "spxElementId", publicName: "spxElementId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", completeInput: "completeInput" }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "inputBoxes", predicate: ["inputBox"], descendants: true }], ngImport: i0, template: "<div class=\"relative text-black flex gap-2 w-full\">\n @for (val of values; track $index) {\n <input #inputBox type=\"text\" maxlength=\"1\" pattern=\"\\d*\" [value]=\"val\" (focus)=\"onFocus($index)\"\n (input)=\"onInput($index, $event)\" [attr.inputMode]=\"this.spxInputMode()\" [attr.pattern]=\"spxCycleConfig().fieldPattern\"\n [class.opacity-50]=\"spxCycleConfig().requiredPositions[$index] === false\"\n [class.bg-sky-100]=\"!this.spxReadonly() && !this.spxSeverity()\"\n [class.bg-red-100]=\"!this.spxReadonly() && this.spxSeverity() === severityError\"\n [class.bg-amber-100]=\"!this.spxReadonly() && this.spxSeverity() === severityWarning\"\n [class.bg-teal-100]=\"!this.spxReadonly() && this.spxSeverity() === severitySuccess\"\n [class.bg-gray-300]=\"this.spxReadonly()\" [class.cursor-not-allowed]=\"this.spxReadonly()\"\n [class.uppercase]=\"this.spxCapitalize()\" [disabled]=\"this.mappedReadonly()\"\n class=\"rounded text-center p-3 font-bold text-lg w-full\" />\n }\n</div>", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
510
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.2", type: SpxInputCycleComponent, isStandalone: true, selector: "spx-input-cycle", inputs: { spxSpeedDial: { classPropertyName: "spxSpeedDial", publicName: "spxSpeedDial", isSignal: true, isRequired: false, transformFunction: null }, spxName: { classPropertyName: "spxName", publicName: "spxName", isSignal: true, isRequired: false, transformFunction: null }, spxAutofocus: { classPropertyName: "spxAutofocus", publicName: "spxAutofocus", isSignal: true, isRequired: false, transformFunction: null }, spxAutocomplete: { classPropertyName: "spxAutocomplete", publicName: "spxAutocomplete", isSignal: true, isRequired: false, transformFunction: null }, spxCycleConfig: { classPropertyName: "spxCycleConfig", publicName: "spxCycleConfig", isSignal: true, isRequired: true, transformFunction: null }, spxInputMode: { classPropertyName: "spxInputMode", publicName: "spxInputMode", isSignal: true, isRequired: false, transformFunction: null }, spxReadonly: { classPropertyName: "spxReadonly", publicName: "spxReadonly", isSignal: true, isRequired: false, transformFunction: null }, spxValidators: { classPropertyName: "spxValidators", publicName: "spxValidators", isSignal: true, isRequired: false, transformFunction: null }, spxCapitalize: { classPropertyName: "spxCapitalize", publicName: "spxCapitalize", isSignal: true, isRequired: false, transformFunction: null }, spxType: { classPropertyName: "spxType", publicName: "spxType", isSignal: true, isRequired: false, transformFunction: null }, spxWasInternalUpdate: { classPropertyName: "spxWasInternalUpdate", publicName: "spxWasInternalUpdate", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, spxElementId: { classPropertyName: "spxElementId", publicName: "spxElementId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", completeInput: "completeInput" }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "inputBoxes", predicate: ["inputBox"], descendants: true }], ngImport: i0, template: "<div class=\"relative text-black flex gap-2 w-full\">\n @for (val of values; track $index) {\n <input #inputBox type=\"text\" maxlength=\"1\" pattern=\"\\d*\" [value]=\"val\" (focus)=\"onFocus($index, $event)\"\n (compositionstart)=\"onCompositionStart()\" (compositionend)=\"onCompositionEnd()\" (input)=\"onInput($index, $event)\"\n (keydown)=\"onKeydown($index, $event)\" (mouseup)=\"onMouseUp($event)\"\n [attr.inputMode]=\"this.spxInputMode()\" [attr.pattern]=\"spxCycleConfig().fieldPattern\"\n [class.opacity-50]=\"spxCycleConfig().requiredPositions[$index] === false\"\n [class.bg-sky-100]=\"!this.spxReadonly() && !this.spxSeverity()\"\n [class.bg-red-100]=\"!this.spxReadonly() && this.spxSeverity() === severityError\"\n [class.bg-amber-100]=\"!this.spxReadonly() && this.spxSeverity() === severityWarning\"\n [class.bg-teal-100]=\"!this.spxReadonly() && this.spxSeverity() === severitySuccess\"\n [class.bg-gray-300]=\"this.spxReadonly()\" [class.cursor-not-allowed]=\"this.spxReadonly()\"\n [class.uppercase]=\"this.spxCapitalize()\" [disabled]=\"this.mappedReadonly()\"\n class=\"rounded text-center p-3 font-bold text-lg w-full\" />\n }\n</div>", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
385
511
|
}
|
|
386
512
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.2", ngImport: i0, type: SpxInputCycleComponent, decorators: [{
|
|
387
513
|
type: Component,
|
|
388
514
|
args: [{ selector: 'spx-input-cycle', imports: [
|
|
389
515
|
ReactiveFormsModule,
|
|
390
516
|
FormsModule,
|
|
391
|
-
], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"relative text-black flex gap-2 w-full\">\n @for (val of values; track $index) {\n <input #inputBox type=\"text\" maxlength=\"1\" pattern=\"\\d*\" [value]=\"val\" (focus)=\"onFocus($index)\"\n (input)=\"onInput($index, $event)\" [attr.inputMode]=\"this.spxInputMode()\" [attr.pattern]=\"spxCycleConfig().fieldPattern\"\n [class.opacity-50]=\"spxCycleConfig().requiredPositions[$index] === false\"\n [class.bg-sky-100]=\"!this.spxReadonly() && !this.spxSeverity()\"\n [class.bg-red-100]=\"!this.spxReadonly() && this.spxSeverity() === severityError\"\n [class.bg-amber-100]=\"!this.spxReadonly() && this.spxSeverity() === severityWarning\"\n [class.bg-teal-100]=\"!this.spxReadonly() && this.spxSeverity() === severitySuccess\"\n [class.bg-gray-300]=\"this.spxReadonly()\" [class.cursor-not-allowed]=\"this.spxReadonly()\"\n [class.uppercase]=\"this.spxCapitalize()\" [disabled]=\"this.mappedReadonly()\"\n class=\"rounded text-center p-3 font-bold text-lg w-full\" />\n }\n</div>" }]
|
|
517
|
+
], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"relative text-black flex gap-2 w-full\">\n @for (val of values; track $index) {\n <input #inputBox type=\"text\" maxlength=\"1\" pattern=\"\\d*\" [value]=\"val\" (focus)=\"onFocus($index, $event)\"\n (compositionstart)=\"onCompositionStart()\" (compositionend)=\"onCompositionEnd()\" (input)=\"onInput($index, $event)\"\n (keydown)=\"onKeydown($index, $event)\" (mouseup)=\"onMouseUp($event)\"\n [attr.inputMode]=\"this.spxInputMode()\" [attr.pattern]=\"spxCycleConfig().fieldPattern\"\n [class.opacity-50]=\"spxCycleConfig().requiredPositions[$index] === false\"\n [class.bg-sky-100]=\"!this.spxReadonly() && !this.spxSeverity()\"\n [class.bg-red-100]=\"!this.spxReadonly() && this.spxSeverity() === severityError\"\n [class.bg-amber-100]=\"!this.spxReadonly() && this.spxSeverity() === severityWarning\"\n [class.bg-teal-100]=\"!this.spxReadonly() && this.spxSeverity() === severitySuccess\"\n [class.bg-gray-300]=\"this.spxReadonly()\" [class.cursor-not-allowed]=\"this.spxReadonly()\"\n [class.uppercase]=\"this.spxCapitalize()\" [disabled]=\"this.mappedReadonly()\"\n class=\"rounded text-center p-3 font-bold text-lg w-full\" />\n }\n</div>" }]
|
|
392
518
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { completeInput: [{
|
|
393
519
|
type: Output
|
|
394
520
|
}], inputBoxes: [{
|