@koobiq/components 19.6.0 → 19.7.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/breadcrumbs/breadcrumbs.scss +0 -4
- package/code-block/code-block-highlight.d.ts +1 -0
- package/core/option/option.d.ts +8 -0
- package/core/validation/validation.d.ts +1 -1
- package/fesm2022/koobiq-components-breadcrumbs.mjs +2 -2
- package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
- package/fesm2022/koobiq-components-code-block.mjs +10 -7
- package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
- package/fesm2022/koobiq-components-core.mjs +31 -13
- package/fesm2022/koobiq-components-core.mjs.map +1 -1
- package/fesm2022/koobiq-components-datepicker.mjs +1 -1
- package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
- package/fesm2022/koobiq-components-file-upload.mjs +4 -4
- package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
- package/fesm2022/koobiq-components-filter-bar.mjs +3 -3
- package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
- package/fesm2022/koobiq-components-form-field.mjs +4 -4
- package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
- package/fesm2022/koobiq-components-modal.mjs +8 -6
- package/fesm2022/koobiq-components-modal.mjs.map +1 -1
- package/fesm2022/koobiq-components-select.mjs +31 -9
- package/fesm2022/koobiq-components-select.mjs.map +1 -1
- package/fesm2022/koobiq-components-tags.mjs +49 -34
- package/fesm2022/koobiq-components-tags.mjs.map +1 -1
- package/fesm2022/koobiq-components-timezone.mjs +4 -4
- package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
- package/fesm2022/koobiq-components-tooltip.mjs +2 -2
- package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
- package/fesm2022/koobiq-components-tree-select.mjs +2 -2
- package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
- package/fesm2022/koobiq-components-tree.mjs +1 -1
- package/fesm2022/koobiq-components-tree.mjs.map +1 -1
- package/form-field/_form-field-theme.scss +10 -2
- package/form-field/form-field-tokens.scss +1 -0
- package/form-field/form-field.scss +19 -0
- package/package.json +4 -4
- package/schematics/ng-add/index.js +2 -2
- package/select/select-tokens.scss +2 -2
- package/select/select.component.d.ts +10 -1
- package/tags/tag-list.component.d.ts +15 -11
- package/tags/tag.component.d.ts +5 -2
- package/timezone/timezone-option-tokens.scss +0 -10
- package/tooltip/_tooltip-theme.scss +5 -1
|
@@ -16,7 +16,7 @@ import { DELETE, SPACE, BACKSPACE, ENTER, ESCAPE, F2, LEFT_ARROW, TAB, HOME, END
|
|
|
16
16
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
17
17
|
import { FocusKeyManager } from '@koobiq/cdk/a11y';
|
|
18
18
|
import { Subject, merge } from 'rxjs';
|
|
19
|
-
import { startWith, filter } from 'rxjs/operators';
|
|
19
|
+
import { startWith, takeUntil, filter } from 'rxjs/operators';
|
|
20
20
|
import { KbqIcon } from '@koobiq/components/icon';
|
|
21
21
|
import { PlatformModule } from '@angular/cdk/platform';
|
|
22
22
|
|
|
@@ -253,9 +253,12 @@ class KbqTag extends KbqColorDirective {
|
|
|
253
253
|
this.editing = signal(false);
|
|
254
254
|
/** Emitted when the tag is selected or deselected. */
|
|
255
255
|
this.selectionChange = new EventEmitter();
|
|
256
|
-
/** Emitted when the tag is destroyed. */
|
|
256
|
+
/** Emitted when the tag is destroyed and leaving the DOM. */
|
|
257
257
|
this.destroyed = new EventEmitter();
|
|
258
|
-
/**
|
|
258
|
+
/**
|
|
259
|
+
* Emitted when a tag is to be removed.
|
|
260
|
+
* Fires on programmatic and UI removal (click or keyboard).
|
|
261
|
+
*/
|
|
259
262
|
this.removed = new EventEmitter();
|
|
260
263
|
this._selected = false;
|
|
261
264
|
this._selectable = false;
|
|
@@ -696,13 +699,21 @@ class KbqTagList {
|
|
|
696
699
|
return merge(...this.tags.map((tag) => tag.onBlur));
|
|
697
700
|
}
|
|
698
701
|
/**
|
|
699
|
-
* Combined stream of all of the child tags'
|
|
702
|
+
* Combined stream of all of the child tags' destroyed events.
|
|
700
703
|
*
|
|
701
704
|
* @docs-private
|
|
702
705
|
*/
|
|
703
706
|
get tagRemoveChanges() {
|
|
704
707
|
return merge(...this.tags.map((tag) => tag.destroyed));
|
|
705
708
|
}
|
|
709
|
+
/**
|
|
710
|
+
* Combined stream of all of the child tags' removal request events.
|
|
711
|
+
*
|
|
712
|
+
* @docs-private
|
|
713
|
+
*/
|
|
714
|
+
get tagBeforeRemoveChanges() {
|
|
715
|
+
return merge(...this.tags.map((tag) => tag.removed));
|
|
716
|
+
}
|
|
706
717
|
/**
|
|
707
718
|
* Combined stream of all of the child tags' edit change events.
|
|
708
719
|
*
|
|
@@ -872,7 +883,8 @@ class KbqTagList {
|
|
|
872
883
|
this.editable = false;
|
|
873
884
|
/**
|
|
874
885
|
* Whether to emit change events when tags are added/removed.
|
|
875
|
-
*
|
|
886
|
+
*
|
|
887
|
+
* @deprecated No longer needed. Will be removed in the next major release.
|
|
876
888
|
*/
|
|
877
889
|
this.emitOnTagChanges = true;
|
|
878
890
|
this._removable = true;
|
|
@@ -912,12 +924,16 @@ class KbqTagList {
|
|
|
912
924
|
* @docs-private
|
|
913
925
|
*/
|
|
914
926
|
this.errorState = false;
|
|
927
|
+
/** True when the next `tags.changes` emission is triggered by a UI action, not programmatic update. */
|
|
928
|
+
this.pendingUIChange = false;
|
|
915
929
|
/**
|
|
916
930
|
* When a tag is destroyed, we store the index of the destroyed tag until the tags
|
|
917
931
|
* query list notifies about the update. This is necessary because we cannot determine an
|
|
918
932
|
* appropriate tag that should receive focus until the array of tags updated completely.
|
|
919
933
|
*/
|
|
920
934
|
this.lastDestroyedTagIndex = null;
|
|
935
|
+
/** Triggers unsubscription from all per-tags streams when tags are reset. */
|
|
936
|
+
this.tagsSubscriptions$ = new Subject();
|
|
921
937
|
/** @docs-private */
|
|
922
938
|
this.onTouched = () => { };
|
|
923
939
|
/** @docs-private */
|
|
@@ -967,8 +983,8 @@ class KbqTagList {
|
|
|
967
983
|
// has changed after it was checked" errors from Angular.
|
|
968
984
|
Promise.resolve().then(() => {
|
|
969
985
|
this.stateChanges.next();
|
|
970
|
-
|
|
971
|
-
|
|
986
|
+
if (currentTags && this.pendingUIChange) {
|
|
987
|
+
this.pendingUIChange = false;
|
|
972
988
|
this.propagateTagsChanges();
|
|
973
989
|
}
|
|
974
990
|
});
|
|
@@ -980,7 +996,7 @@ class KbqTagList {
|
|
|
980
996
|
ngOnDestroy() {
|
|
981
997
|
this.stateChanges.complete();
|
|
982
998
|
this.focusMonitor.stopMonitoring(this.elementRef);
|
|
983
|
-
this.
|
|
999
|
+
this.tagsSubscriptions$.next();
|
|
984
1000
|
}
|
|
985
1001
|
/** @docs-private */
|
|
986
1002
|
updateErrorState() {
|
|
@@ -994,6 +1010,10 @@ class KbqTagList {
|
|
|
994
1010
|
this.stateChanges.next();
|
|
995
1011
|
}
|
|
996
1012
|
}
|
|
1013
|
+
/** Notifies that the next `tags.changes` emission is UI-initiated. */
|
|
1014
|
+
notifyPendingTagChange() {
|
|
1015
|
+
this.pendingUIChange = true;
|
|
1016
|
+
}
|
|
997
1017
|
/**
|
|
998
1018
|
* Associates an HTML input element with this tag list.
|
|
999
1019
|
*
|
|
@@ -1223,32 +1243,14 @@ class KbqTagList {
|
|
|
1223
1243
|
this.changeDetectorRef.markForCheck();
|
|
1224
1244
|
}
|
|
1225
1245
|
resetTags() {
|
|
1226
|
-
this.
|
|
1246
|
+
this.tagsSubscriptions$.next();
|
|
1227
1247
|
this.listenToTagsFocus();
|
|
1228
1248
|
this.listenToTagsRemoved();
|
|
1229
1249
|
this.listenToTagsEdit();
|
|
1230
1250
|
}
|
|
1231
|
-
dropSubscriptions() {
|
|
1232
|
-
if (this.tagFocusSubscription) {
|
|
1233
|
-
this.tagFocusSubscription.unsubscribe();
|
|
1234
|
-
this.tagFocusSubscription = null;
|
|
1235
|
-
}
|
|
1236
|
-
if (this.tagBlurSubscription) {
|
|
1237
|
-
this.tagBlurSubscription.unsubscribe();
|
|
1238
|
-
this.tagBlurSubscription = null;
|
|
1239
|
-
}
|
|
1240
|
-
if (this.tagRemoveSubscription) {
|
|
1241
|
-
this.tagRemoveSubscription.unsubscribe();
|
|
1242
|
-
this.tagRemoveSubscription = null;
|
|
1243
|
-
}
|
|
1244
|
-
if (this.tagEditSubscription) {
|
|
1245
|
-
this.tagEditSubscription.unsubscribe();
|
|
1246
|
-
this.tagEditSubscription = null;
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
1251
|
/** Listens to user-generated selection events on each tag. */
|
|
1250
1252
|
listenToTagsFocus() {
|
|
1251
|
-
this.
|
|
1253
|
+
this.tagFocusChanges.pipe(takeUntil(this.tagsSubscriptions$)).subscribe(({ tag, origin }) => {
|
|
1252
1254
|
const tagIndex = this.tags.toArray().indexOf(tag);
|
|
1253
1255
|
if (this.isValidIndex(tagIndex)) {
|
|
1254
1256
|
this.keyManager.setFocusOrigin(origin);
|
|
@@ -1256,13 +1258,13 @@ class KbqTagList {
|
|
|
1256
1258
|
}
|
|
1257
1259
|
this.stateChanges.next();
|
|
1258
1260
|
});
|
|
1259
|
-
this.
|
|
1261
|
+
this.tagBlurChanges.pipe(takeUntil(this.tagsSubscriptions$)).subscribe(() => {
|
|
1260
1262
|
this.blur();
|
|
1261
1263
|
this.stateChanges.next();
|
|
1262
1264
|
});
|
|
1263
1265
|
}
|
|
1264
1266
|
listenToTagsRemoved() {
|
|
1265
|
-
this.
|
|
1267
|
+
this.tagRemoveChanges.pipe(takeUntil(this.tagsSubscriptions$)).subscribe((event) => {
|
|
1266
1268
|
const tag = event.tag;
|
|
1267
1269
|
const tagIndex = this.tags.toArray().indexOf(event.tag);
|
|
1268
1270
|
// In case the tag that will be removed is currently focused, we temporarily store
|
|
@@ -1272,10 +1274,14 @@ class KbqTagList {
|
|
|
1272
1274
|
this.lastDestroyedTagIndex = tagIndex;
|
|
1273
1275
|
}
|
|
1274
1276
|
});
|
|
1277
|
+
// Set the pending flag so the subsequent `tags.changes` is treated as UI action.
|
|
1278
|
+
this.tagBeforeRemoveChanges
|
|
1279
|
+
.pipe(takeUntil(this.tagsSubscriptions$))
|
|
1280
|
+
.subscribe(() => (this.pendingUIChange = true));
|
|
1275
1281
|
}
|
|
1276
1282
|
listenToTagsEdit() {
|
|
1277
|
-
this.
|
|
1278
|
-
.pipe(filter(({ type }) => type === 'submit'))
|
|
1283
|
+
this.tagEditChanges
|
|
1284
|
+
.pipe(filter(({ type }) => type === 'submit'), takeUntil(this.tagsSubscriptions$))
|
|
1279
1285
|
.subscribe(() => this.propagateTagsChanges());
|
|
1280
1286
|
}
|
|
1281
1287
|
/** Checks whether any of the tags is focused. */
|
|
@@ -1300,6 +1306,7 @@ class KbqTagList {
|
|
|
1300
1306
|
this.dropList.dropped
|
|
1301
1307
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1302
1308
|
.subscribe(({ currentIndex, previousIndex, event, item }) => {
|
|
1309
|
+
this.pendingUIChange = true;
|
|
1303
1310
|
const { tag } = item.data;
|
|
1304
1311
|
this.dropped.emit({ currentIndex, previousIndex, event, tag });
|
|
1305
1312
|
});
|
|
@@ -1509,12 +1516,16 @@ class KbqTagInput {
|
|
|
1509
1516
|
}
|
|
1510
1517
|
/** @docs-private */
|
|
1511
1518
|
onKeydown(event) {
|
|
1519
|
+
const isSeparatorKey = this.isSeparatorKey(event);
|
|
1512
1520
|
if (!this.inputElement.value) {
|
|
1521
|
+
if (isSeparatorKey) {
|
|
1522
|
+
event.preventDefault();
|
|
1523
|
+
}
|
|
1513
1524
|
this._tagList.keydown(event);
|
|
1514
1525
|
event.stopPropagation();
|
|
1515
1526
|
return;
|
|
1516
1527
|
}
|
|
1517
|
-
if (
|
|
1528
|
+
if (isSeparatorKey) {
|
|
1518
1529
|
this.emitTagEnd();
|
|
1519
1530
|
event.preventDefault();
|
|
1520
1531
|
}
|
|
@@ -1543,6 +1554,7 @@ class KbqTagInput {
|
|
|
1543
1554
|
if (!this.hasControl() || (this.hasControl() && !this.ngControl.invalid)) {
|
|
1544
1555
|
if (this.distinct && this.hasDuplicates)
|
|
1545
1556
|
return;
|
|
1557
|
+
this._tagList?.notifyPendingTagChange();
|
|
1546
1558
|
this.tagEnd.emit({ input: this.inputElement, value: this.trimValue(this.inputElement.value) });
|
|
1547
1559
|
}
|
|
1548
1560
|
}
|
|
@@ -1576,6 +1588,9 @@ class KbqTagInput {
|
|
|
1576
1588
|
const tagValues = this._tagList.tags.map(({ value }) => value);
|
|
1577
1589
|
items = items.filter((item) => !tagValues.includes(item));
|
|
1578
1590
|
}
|
|
1591
|
+
if (items.length) {
|
|
1592
|
+
this._tagList?.notifyPendingTagChange();
|
|
1593
|
+
}
|
|
1579
1594
|
items.forEach((item) => this.tagEnd.emit({ input: this.inputElement, value: item }));
|
|
1580
1595
|
$event.preventDefault();
|
|
1581
1596
|
$event.stopPropagation();
|
|
@@ -1616,7 +1631,7 @@ class KbqTagInput {
|
|
|
1616
1631
|
}
|
|
1617
1632
|
/** Checks whether a keycode is one of the configured separators. */
|
|
1618
1633
|
isSeparatorKey(event) {
|
|
1619
|
-
return this.separators.some((separator) => separator.key === event.key && !event
|
|
1634
|
+
return this.separators.some((separator) => separator.key === event.key && !hasModifierKey(event));
|
|
1620
1635
|
}
|
|
1621
1636
|
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: KbqTagInput, deps: [{ token: i0.ElementRef }, { token: KBQ_TAGS_DEFAULT_OPTIONS }, { token: i1$1.KbqTrim, optional: true, self: true }, { token: i3.NgControl, optional: true, self: true }, { token: i3$1.KbqAutocompleteTrigger, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1622
1637
|
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.20", type: KbqTagInput, isStandalone: true, selector: "input[kbqTagInputFor]", inputs: { separatorKeyCodes: ["kbqTagInputSeparatorKeyCodes", "separatorKeyCodes"], distinct: "distinct", placeholder: "placeholder", id: "id", tagList: ["kbqTagInputFor", "tagList"], addOnBlur: ["kbqTagInputAddOnBlur", "addOnBlur"], addOnPaste: ["kbqTagInputAddOnPaste", "addOnPaste", booleanAttribute], disabled: "disabled" }, outputs: { tagEnd: "kbqTagInputTokenEnd" }, host: { listeners: { "keydown": "onKeydown($event)", "blur": "blur($event)", "focus": "onFocus()", "input": "onInput()", "paste": "onPaste($event)" }, properties: { "id": "id", "attr.disabled": "disabled || null", "attr.placeholder": "placeholder || null" }, classAttribute: "kbq-tag-input" }, exportAs: ["kbqTagInput", "kbqTagInputFor"], usesOnChanges: true, hostDirectives: [{ directive: i1.KbqFieldSizingContent }], ngImport: i0 }); }
|