@progress/kendo-angular-listbox 24.0.0-develop.8 → 24.0.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.
@@ -4,7 +4,7 @@
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  "use strict";
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.tsInterfaceTransformer = exports.tsPropertyValueTransformer = exports.tsPropertyTransformer = exports.tsComponentPropertyRemoval = exports.attributeRemoval = exports.attributeValueUpdate = exports.attributeNameValueUpdate = exports.attributeNameUpdate = exports.eventUpdate = exports.htmlTransformer = exports.blockTextElements = void 0;
7
+ exports.tsInterfaceTransformer = exports.tsPropertyValueTransformer = exports.tsPropertyTransformer = exports.tsComponentPropertyRemoval = exports.attributeConditionalRemoval = exports.attributeRemoval = exports.attributeValueUpdate = exports.attributeNameValueUpdate = exports.attributeNameUpdate = exports.eventUpdate = exports.htmlTransformer = exports.blockTextElements = void 0;
8
8
  exports.hasKendoInTemplate = hasKendoInTemplate;
9
9
  exports.isImportedFromPackage = isImportedFromPackage;
10
10
  exports.tsPropertyRemoval = tsPropertyRemoval;
@@ -345,6 +345,34 @@ const attributeRemoval = (templateContent, tagName, attributeName, propertyToRem
345
345
  });
346
346
  };
347
347
  exports.attributeRemoval = attributeRemoval;
348
+ /**
349
+ * Removes an attribute from a tag only when its value matches one of the specified values.
350
+ * Handles both static (`attr="value"`) and bound (`[attr]="'value'"`) forms.
351
+ *
352
+ * @param templateContent - The template string content to transform
353
+ * @param tagName - The HTML tag name to target (e.g., 'kendo-button')
354
+ * @param attributeName - The attribute name to conditionally remove
355
+ * @param values - The attribute values that trigger removal
356
+ * @returns The transformed template content
357
+ */
358
+ const attributeConditionalRemoval = (templateContent, tagName, attributeName, values) => {
359
+ const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
360
+ const escapedTag = escapeRegex(tagName);
361
+ const escapedAttr = escapeRegex(attributeName);
362
+ // Remove bound attributes [attribute]="value"
363
+ const boundAttributePattern = new RegExp(`(<${escapedTag}[^>]*?)\\s+\\[${escapedAttr}\\]\\s*=\\s*("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?'|[^\\s>]+)([^>]*?>)`, 'gi');
364
+ // Remove static attributes attribute="value"
365
+ const staticAttributePattern = new RegExp(`(<${escapedTag}[^>]*?)\\s+${escapedAttr}\\s*=\\s*("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?'|[^\\s>]+)([^>]*?>)`, 'gi');
366
+ // Strip outer and inner quotes to extract the raw value for comparison
367
+ const matchesValue = (raw) => {
368
+ const inner = raw.replace(/^["']|["']$/g, '').replace(/^['"]|['"]$/g, '');
369
+ return values.includes(inner);
370
+ };
371
+ let result = templateContent.replace(boundAttributePattern, (match, prefix, value, suffix) => matchesValue(value) ? prefix + suffix : match);
372
+ result = result.replace(staticAttributePattern, (match, prefix, value, suffix) => matchesValue(value) ? prefix + suffix : match);
373
+ return result;
374
+ };
375
+ exports.attributeConditionalRemoval = attributeConditionalRemoval;
348
376
  function tsPropertyRemoval(source, rootSource, j, packageName, typeName, propertyName) {
349
377
  if (source.includes(typeName)) {
350
378
  if (!isImportedFromPackage(rootSource, j, packageName, typeName)) {
@@ -441,8 +469,31 @@ function tsPropertyRemoval(source, rootSource, j, packageName, typeName, propert
441
469
  }
442
470
  }
443
471
  });
444
- // Handle return statements with object literals
472
+ // Handle return statements with object literals, but only when the enclosing
473
+ // function's declared return type matches typeName. This prevents removing
474
+ // unrelated propertyName keys from object literals returned in other functions.
475
+ const enclosingFunctionReturnsType = (nodePath) => {
476
+ let current = nodePath.parent;
477
+ while (current) {
478
+ const node = current.node;
479
+ if (node.type === 'FunctionDeclaration' ||
480
+ node.type === 'FunctionExpression' ||
481
+ node.type === 'ArrowFunctionExpression' ||
482
+ node.type === 'ClassMethod' ||
483
+ node.type === 'ObjectMethod') {
484
+ return !!(node.returnType &&
485
+ node.returnType.typeAnnotation?.type === 'TSTypeReference' &&
486
+ node.returnType.typeAnnotation.typeName?.type === 'Identifier' &&
487
+ node.returnType.typeAnnotation.typeName.name === typeName);
488
+ }
489
+ current = current.parent;
490
+ }
491
+ return false;
492
+ };
445
493
  rootSource.find(j.ReturnStatement).forEach((path) => {
494
+ if (!enclosingFunctionReturnsType(path)) {
495
+ return;
496
+ }
446
497
  if (path.node.argument && path.node.argument.type === 'ObjectExpression') {
447
498
  const properties = path.node.argument.properties;
448
499
  const propIndex = properties.findIndex((p) => p.type === 'ObjectProperty' &&
@@ -491,22 +542,6 @@ function tsPropertyRemoval(source, rootSource, j, packageName, typeName, propert
491
542
  statement.remove();
492
543
  }
493
544
  });
494
- // Handle nested member expressions like chatConfig.chat.modelFields.pinnedByField
495
- rootSource
496
- .find(j.AssignmentExpression, {
497
- left: {
498
- type: 'MemberExpression',
499
- object: {
500
- type: 'MemberExpression',
501
- },
502
- property: {
503
- name: propertyName,
504
- },
505
- },
506
- })
507
- .forEach((path) => {
508
- j(path).closest(j.ExpressionStatement).remove();
509
- });
510
545
  return rootSource;
511
546
  }
512
547
  }
package/directives.d.ts CHANGED
@@ -7,7 +7,8 @@ import { ItemSelectableDirective } from "./item-selectable.directive";
7
7
  import { ItemTemplateDirective } from "./item-template.directive";
8
8
  import { ListBoxComponent } from "./listbox.component";
9
9
  import { CustomMessagesComponent } from "./localization/custom-messages.component";
10
+ import { NoDataTemplateDirective } from "./no-data-template.directive";
10
11
  /**
11
12
  * Utility array that contains all `@progress/kendo-angular-listbox` related components and directives
12
13
  */
13
- export declare const KENDO_LISTBOX: readonly [typeof ListBoxComponent, typeof ItemTemplateDirective, typeof ItemSelectableDirective, typeof DataBindingDirective, typeof CustomMessagesComponent];
14
+ export declare const KENDO_LISTBOX: readonly [typeof ListBoxComponent, typeof ItemTemplateDirective, typeof ItemSelectableDirective, typeof NoDataTemplateDirective, typeof DataBindingDirective, typeof CustomMessagesComponent];
@@ -7,12 +7,13 @@ import { EventEmitter, Injectable, Directive, HostListener, HostBinding, Input,
7
7
  import { validatePackage } from '@progress/kendo-licensing';
8
8
  import { Subscription } from 'rxjs';
9
9
  import { getter } from '@progress/kendo-common';
10
- import { caretAltUpIcon, caretAltDownIcon, caretAltRightIcon, caretAltLeftIcon, caretDoubleAltRightIcon, caretDoubleAltLeftIcon, xIcon } from '@progress/kendo-svg-icons';
10
+ import { chevronUpIcon, chevronDownIcon, chevronRightIcon, chevronLeftIcon, chevronDoubleRightIcon, chevronDoubleLeftIcon, xIcon } from '@progress/kendo-svg-icons';
11
11
  import { ButtonComponent } from '@progress/kendo-angular-buttons';
12
- import { normalizeKeys, Keys, isPresent as isPresent$1, TemplateContextDirective, isChanged, ResizeBatchService } from '@progress/kendo-angular-common';
12
+ import { normalizeKeys, Keys, isPresent as isPresent$1, TemplateContextDirective, KENDO_WEBMCP_HOST, isChanged, ResizeBatchService } from '@progress/kendo-angular-common';
13
13
  import { take } from 'rxjs/operators';
14
14
  import * as i1 from '@progress/kendo-angular-l10n';
15
15
  import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
16
+ import { NgTemplateOutlet } from '@angular/common';
16
17
  import { IconsService } from '@progress/kendo-angular-icons';
17
18
  import { PopupService } from '@progress/kendo-angular-popup';
18
19
 
@@ -24,8 +25,8 @@ const packageMetadata = {
24
25
  productName: 'Kendo UI for Angular',
25
26
  productCode: 'KENDOUIANGULAR',
26
27
  productCodes: ['KENDOUIANGULAR'],
27
- publishDate: 1777363315,
28
- version: '24.0.0-develop.8',
28
+ publishDate: 1779273575,
29
+ version: '24.0.0',
29
30
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning'
30
31
  };
31
32
 
@@ -227,6 +228,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
227
228
  }]
228
229
  }], ctorParameters: () => [{ type: i0.TemplateRef }] });
229
230
 
231
+ /**
232
+ * Lets you customize the content shown when the ListBox has no data to display.
233
+ * To define a no-data template, nest an `<ng-template>` tag
234
+ * with the `kendoListBoxNoDataTemplate` directive inside the `<kendo-listbox>` tag
235
+ * ([see example](https://www.telerik.com/kendo-angular-ui/components/listbox/templates#no-data-template)).
236
+ *
237
+ * @example
238
+ * ```html
239
+ * <kendo-listbox [data]="[]">
240
+ * <ng-template kendoListBoxNoDataTemplate>
241
+ * No items to display.
242
+ * </ng-template>
243
+ * </kendo-listbox>
244
+ * ```
245
+ */
246
+ class NoDataTemplateDirective {
247
+ templateRef;
248
+ constructor(templateRef) {
249
+ this.templateRef = templateRef;
250
+ }
251
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: NoDataTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
252
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.20", type: NoDataTemplateDirective, isStandalone: true, selector: "[kendoListBoxNoDataTemplate]", ngImport: i0 });
253
+ }
254
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: NoDataTemplateDirective, decorators: [{
255
+ type: Directive,
256
+ args: [{
257
+ selector: '[kendoListBoxNoDataTemplate]',
258
+ standalone: true
259
+ }]
260
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
261
+
230
262
  /**
231
263
  * @hidden
232
264
  */
@@ -238,38 +270,38 @@ const allTools = [
238
270
  {
239
271
  name: 'moveUp',
240
272
  label: 'Move Up',
241
- icon: 'caret-alt-up',
242
- svgIcon: caretAltUpIcon
273
+ icon: 'chevron-up',
274
+ svgIcon: chevronUpIcon
243
275
  },
244
276
  {
245
277
  name: 'moveDown',
246
278
  label: 'Move Down',
247
- icon: 'caret-alt-down',
248
- svgIcon: caretAltDownIcon
279
+ icon: 'chevron-down',
280
+ svgIcon: chevronDownIcon
249
281
  },
250
282
  {
251
283
  name: 'transferTo',
252
284
  label: 'Transfer To',
253
- icon: 'caret-alt-right',
254
- svgIcon: caretAltRightIcon
285
+ icon: 'chevron-right',
286
+ svgIcon: chevronRightIcon
255
287
  },
256
288
  {
257
289
  name: 'transferFrom',
258
290
  label: 'Transfer From',
259
- icon: 'caret-alt-left',
260
- svgIcon: caretAltLeftIcon
291
+ icon: 'chevron-left',
292
+ svgIcon: chevronLeftIcon
261
293
  },
262
294
  {
263
295
  name: 'transferAllTo',
264
296
  label: 'Transfer All To',
265
- icon: 'caret-double-alt-right',
266
- svgIcon: caretDoubleAltRightIcon
297
+ icon: 'chevron-double-right',
298
+ svgIcon: chevronDoubleRightIcon
267
299
  },
268
300
  {
269
301
  name: 'transferAllFrom',
270
302
  label: 'Transfer All From',
271
- icon: 'caret-double-alt-left',
272
- svgIcon: caretDoubleAltLeftIcon
303
+ icon: 'chevron-double-left',
304
+ svgIcon: chevronDoubleLeftIcon
273
305
  },
274
306
  {
275
307
  name: 'remove',
@@ -888,6 +920,10 @@ class ListBoxComponent {
888
920
  * @hidden
889
921
  */
890
922
  itemTemplate;
923
+ /**
924
+ * @hidden
925
+ */
926
+ noDataTemplate;
891
927
  /**
892
928
  * @hidden
893
929
  */
@@ -1027,11 +1063,11 @@ class ListBoxComponent {
1027
1063
  /**
1028
1064
  * @hidden
1029
1065
  */
1030
- caretAltLeftIcon = caretAltLeftIcon;
1066
+ chevronLeftIcon = chevronLeftIcon;
1031
1067
  /**
1032
1068
  * @hidden
1033
1069
  */
1034
- caretAltRightIcon = caretAltRightIcon;
1070
+ chevronRightIcon = chevronRightIcon;
1035
1071
  localizationSubscription;
1036
1072
  _size;
1037
1073
  subs = new Subscription();
@@ -1155,25 +1191,31 @@ class ListBoxComponent {
1155
1191
  * @hidden
1156
1192
  */
1157
1193
  toolIcon(icon) {
1158
- return this.direction === 'ltr' ?
1159
- icon :
1160
- icon === 'caret-alt-left' ?
1161
- 'caret-alt-right' :
1162
- icon === 'caret-alt-right' ?
1163
- 'caret-alt-left' :
1164
- icon;
1194
+ if (this.direction === 'ltr') {
1195
+ return icon;
1196
+ }
1197
+ if (icon === 'chevron-left') {
1198
+ return 'chevron-right';
1199
+ }
1200
+ if (icon === 'chevron-right') {
1201
+ return 'chevron-left';
1202
+ }
1203
+ return icon;
1165
1204
  }
1166
1205
  /**
1167
1206
  * @hidden
1168
1207
  */
1169
1208
  toolSVGIcon(icon) {
1170
- return this.direction === 'ltr' ?
1171
- icon :
1172
- icon === this.caretAltLeftIcon ?
1173
- this.caretAltRightIcon :
1174
- icon === this.caretAltRightIcon ?
1175
- this.caretAltLeftIcon :
1176
- icon;
1209
+ if (this.direction === 'ltr') {
1210
+ return icon;
1211
+ }
1212
+ if (icon === this.chevronLeftIcon) {
1213
+ return this.chevronRightIcon;
1214
+ }
1215
+ if (icon === this.chevronRightIcon) {
1216
+ return this.chevronLeftIcon;
1217
+ }
1218
+ return icon;
1177
1219
  }
1178
1220
  initSubscriptions(navService, hostEl, toolsRef) {
1179
1221
  this.subs.add(navService.onShiftSelectedItem.subscribe((actionToPerform) => this.performAction(actionToPerform)));
@@ -1352,7 +1394,8 @@ class ListBoxComponent {
1352
1394
  provide: L10N_PREFIX,
1353
1395
  useValue: 'kendo.listbox'
1354
1396
  },
1355
- ], queries: [{ propertyName: "itemTemplate", first: true, predicate: ItemTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "listboxElement", first: true, predicate: ["listbox"], descendants: true }, { propertyName: "toolbarElement", first: true, predicate: ["toolbar"], descendants: true }, { propertyName: "listboxItems", predicate: ["listboxItems"], descendants: true }, { propertyName: "tools", predicate: ["tools"], descendants: true }], ngImport: i0, template: `
1397
+ { provide: KENDO_WEBMCP_HOST, useExisting: forwardRef(() => ListBoxComponent) }
1398
+ ], queries: [{ propertyName: "itemTemplate", first: true, predicate: ItemTemplateDirective, descendants: true }, { propertyName: "noDataTemplate", first: true, predicate: NoDataTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "listboxElement", first: true, predicate: ["listbox"], descendants: true }, { propertyName: "toolbarElement", first: true, predicate: ["toolbar"], descendants: true }, { propertyName: "listboxItems", predicate: ["listboxItems"], descendants: true }, { propertyName: "tools", predicate: ["tools"], descendants: true }], ngImport: i0, template: `
1356
1399
  <ng-container kendoListBoxLocalizedMessages
1357
1400
  i18n-moveUp="kendo.listbox.moveUp|The title of the Move Up button"
1358
1401
  moveUp="Move Up"
@@ -1395,8 +1438,8 @@ class ListBoxComponent {
1395
1438
  [icon]="toolIcon(tool.icon)"
1396
1439
  [svgIcon]="toolSVGIcon(tool.svgIcon)"
1397
1440
  [attr.title]="messageFor(tool.name)"
1441
+ [attr.aria-label]="messageFor(tool.name)"
1398
1442
  (click)="performAction(tool.name)"
1399
- role="button"
1400
1443
  type="button"
1401
1444
  ></button>
1402
1445
  }
@@ -1404,7 +1447,7 @@ class ListBoxComponent {
1404
1447
  }
1405
1448
  <div class="k-list-scroller k-selectable">
1406
1449
  <div class="{{ listClasses }}">
1407
- @if (data.length > 0) {
1450
+ @if (data?.length > 0) {
1408
1451
  <div
1409
1452
  class="k-list-content"
1410
1453
  >
@@ -1413,7 +1456,7 @@ class ListBoxComponent {
1413
1456
  class="k-list-ul"
1414
1457
  role="listbox"
1415
1458
  [attr.aria-label]="listboxLabel"
1416
- [attr.aria-multiselectable]="selectable === 'multiple'"
1459
+ [attr.aria-multiselectable]="selectable === 'multiple' ? true : null"
1417
1460
  >
1418
1461
  @for (item of data; track item; let i = $index) {
1419
1462
  <li
@@ -1425,7 +1468,7 @@ class ListBoxComponent {
1425
1468
  [attr.aria-selected]="selectedIndices.indexOf(i) >= 0"
1426
1469
  [index]="i"
1427
1470
  [class.k-disabled]="itemDisabled(item)"
1428
- [attr.aria-disabled]="itemDisabled(item)"
1471
+ [attr.aria-disabled]="itemDisabled(item) ? true : null"
1429
1472
  >
1430
1473
  @if (itemTemplate) {
1431
1474
  <ng-template
@@ -1443,14 +1486,18 @@ class ListBoxComponent {
1443
1486
  </ul>
1444
1487
  </div>
1445
1488
  }
1446
- @if (data.length === 0) {
1447
- <span
1448
- class="k-nodata"
1449
- >{{ messageFor('noDataText') }}</span>
1489
+ @if (!data?.length) {
1490
+ <span class="k-nodata">
1491
+ @if (noDataTemplate?.templateRef) {
1492
+ <ng-template [ngTemplateOutlet]="noDataTemplate.templateRef"></ng-template>
1493
+ } @else {
1494
+ {{ messageFor('noDataText') }}
1495
+ }
1496
+ </span>
1450
1497
  }
1451
1498
  </div>
1452
1499
  </div>
1453
- `, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoListBoxLocalizedMessages]" }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: ItemSelectableDirective, selector: "[kendoListBoxItemSelectable]", inputs: ["index"] }, { kind: "directive", type: TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }] });
1500
+ `, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoListBoxLocalizedMessages]" }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: ItemSelectableDirective, selector: "[kendoListBoxItemSelectable]", inputs: ["index"] }, { kind: "directive", type: TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
1454
1501
  }
1455
1502
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ListBoxComponent, decorators: [{
1456
1503
  type: Component,
@@ -1464,6 +1511,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1464
1511
  provide: L10N_PREFIX,
1465
1512
  useValue: 'kendo.listbox'
1466
1513
  },
1514
+ { provide: KENDO_WEBMCP_HOST, useExisting: forwardRef(() => ListBoxComponent) }
1467
1515
  ],
1468
1516
  template: `
1469
1517
  <ng-container kendoListBoxLocalizedMessages
@@ -1508,8 +1556,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1508
1556
  [icon]="toolIcon(tool.icon)"
1509
1557
  [svgIcon]="toolSVGIcon(tool.svgIcon)"
1510
1558
  [attr.title]="messageFor(tool.name)"
1559
+ [attr.aria-label]="messageFor(tool.name)"
1511
1560
  (click)="performAction(tool.name)"
1512
- role="button"
1513
1561
  type="button"
1514
1562
  ></button>
1515
1563
  }
@@ -1517,7 +1565,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1517
1565
  }
1518
1566
  <div class="k-list-scroller k-selectable">
1519
1567
  <div class="{{ listClasses }}">
1520
- @if (data.length > 0) {
1568
+ @if (data?.length > 0) {
1521
1569
  <div
1522
1570
  class="k-list-content"
1523
1571
  >
@@ -1526,7 +1574,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1526
1574
  class="k-list-ul"
1527
1575
  role="listbox"
1528
1576
  [attr.aria-label]="listboxLabel"
1529
- [attr.aria-multiselectable]="selectable === 'multiple'"
1577
+ [attr.aria-multiselectable]="selectable === 'multiple' ? true : null"
1530
1578
  >
1531
1579
  @for (item of data; track item; let i = $index) {
1532
1580
  <li
@@ -1538,7 +1586,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1538
1586
  [attr.aria-selected]="selectedIndices.indexOf(i) >= 0"
1539
1587
  [index]="i"
1540
1588
  [class.k-disabled]="itemDisabled(item)"
1541
- [attr.aria-disabled]="itemDisabled(item)"
1589
+ [attr.aria-disabled]="itemDisabled(item) ? true : null"
1542
1590
  >
1543
1591
  @if (itemTemplate) {
1544
1592
  <ng-template
@@ -1556,16 +1604,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1556
1604
  </ul>
1557
1605
  </div>
1558
1606
  }
1559
- @if (data.length === 0) {
1560
- <span
1561
- class="k-nodata"
1562
- >{{ messageFor('noDataText') }}</span>
1607
+ @if (!data?.length) {
1608
+ <span class="k-nodata">
1609
+ @if (noDataTemplate?.templateRef) {
1610
+ <ng-template [ngTemplateOutlet]="noDataTemplate.templateRef"></ng-template>
1611
+ } @else {
1612
+ {{ messageFor('noDataText') }}
1613
+ }
1614
+ </span>
1563
1615
  }
1564
1616
  </div>
1565
1617
  </div>
1566
1618
  `,
1567
1619
  standalone: true,
1568
- imports: [LocalizedMessagesDirective, ButtonComponent, ItemSelectableDirective, TemplateContextDirective]
1620
+ imports: [LocalizedMessagesDirective, ButtonComponent, ItemSelectableDirective, TemplateContextDirective, NgTemplateOutlet]
1569
1621
  }]
1570
1622
  }], ctorParameters: () => [{ type: KeyboardNavigationService }, { type: ListBoxSelectionService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }], propDecorators: { listboxClassName: [{
1571
1623
  type: HostBinding,
@@ -1576,6 +1628,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1576
1628
  }], itemTemplate: [{
1577
1629
  type: ContentChild,
1578
1630
  args: [ItemTemplateDirective]
1631
+ }], noDataTemplate: [{
1632
+ type: ContentChild,
1633
+ args: [NoDataTemplateDirective, { static: false }]
1579
1634
  }], listboxElement: [{
1580
1635
  type: ViewChild,
1581
1636
  args: ['listbox']
@@ -1952,6 +2007,7 @@ const KENDO_LISTBOX = [
1952
2007
  ListBoxComponent,
1953
2008
  ItemTemplateDirective,
1954
2009
  ItemSelectableDirective,
2010
+ NoDataTemplateDirective,
1955
2011
  DataBindingDirective,
1956
2012
  CustomMessagesComponent,
1957
2013
  ];
@@ -1962,7 +2018,7 @@ const KENDO_LISTBOX = [
1962
2018
  */
1963
2019
  class ListBoxModule {
1964
2020
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ListBoxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1965
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.20", ngImport: i0, type: ListBoxModule, imports: [ListBoxComponent, ItemTemplateDirective, ItemSelectableDirective, DataBindingDirective, CustomMessagesComponent], exports: [ListBoxComponent, ItemTemplateDirective, ItemSelectableDirective, DataBindingDirective, CustomMessagesComponent] });
2021
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.20", ngImport: i0, type: ListBoxModule, imports: [ListBoxComponent, ItemTemplateDirective, ItemSelectableDirective, NoDataTemplateDirective, DataBindingDirective, CustomMessagesComponent], exports: [ListBoxComponent, ItemTemplateDirective, ItemSelectableDirective, NoDataTemplateDirective, DataBindingDirective, CustomMessagesComponent] });
1966
2022
  static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ListBoxModule, providers: [IconsService, PopupService, ResizeBatchService], imports: [ListBoxComponent] });
1967
2023
  }
1968
2024
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ListBoxModule, decorators: [{
@@ -1978,5 +2034,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1978
2034
  * Generated bundle index. Do not edit.
1979
2035
  */
1980
2036
 
1981
- export { CustomMessagesComponent, DataBindingDirective, ItemSelectableDirective, ItemTemplateDirective, KENDO_LISTBOX, ListBoxComponent, ListBoxModule, LocalizedMessagesDirective };
2037
+ export { CustomMessagesComponent, DataBindingDirective, ItemSelectableDirective, ItemTemplateDirective, KENDO_LISTBOX, ListBoxComponent, ListBoxModule, LocalizedMessagesDirective, NoDataTemplateDirective };
1982
2038
 
package/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export { ListBoxComponent } from './listbox.component';
6
6
  export { ListBoxModule } from './listbox.module';
7
7
  export { DataBindingDirective } from './data-binding.directive';
8
8
  export { ItemTemplateDirective } from './item-template.directive';
9
+ export { NoDataTemplateDirective } from './no-data-template.directive';
9
10
  export { ItemSelectableDirective } from './item-selectable.directive';
10
11
  export { ListBoxSize } from './size';
11
12
  export { ActionName } from './toolbar';
@@ -5,6 +5,7 @@
5
5
  import { AfterViewInit, ChangeDetectorRef, ElementRef, EventEmitter, NgZone, OnDestroy, OnInit, QueryList, Renderer2 } from '@angular/core';
6
6
  import { ListBoxSelectionEvent, ListBoxSelectionService } from './selection.service';
7
7
  import { ItemTemplateDirective } from './item-template.directive';
8
+ import { NoDataTemplateDirective } from './no-data-template.directive';
8
9
  import { Direction } from './util';
9
10
  import { ListBoxSize } from './size';
10
11
  import { ActionName, ListBoxToolbarConfig, Tool } from './toolbar';
@@ -62,6 +63,10 @@ export declare class ListBoxComponent implements OnInit, AfterViewInit, OnDestro
62
63
  * @hidden
63
64
  */
64
65
  itemTemplate: ItemTemplateDirective;
66
+ /**
67
+ * @hidden
68
+ */
69
+ noDataTemplate: NoDataTemplateDirective;
65
70
  /**
66
71
  * @hidden
67
72
  */
@@ -174,11 +179,11 @@ export declare class ListBoxComponent implements OnInit, AfterViewInit, OnDestro
174
179
  /**
175
180
  * @hidden
176
181
  */
177
- caretAltLeftIcon: SVGIcon;
182
+ chevronLeftIcon: SVGIcon;
178
183
  /**
179
184
  * @hidden
180
185
  */
181
- caretAltRightIcon: SVGIcon;
186
+ chevronRightIcon: SVGIcon;
182
187
  private localizationSubscription;
183
188
  private _size;
184
189
  private subs;
@@ -233,5 +238,5 @@ export declare class ListBoxComponent implements OnInit, AfterViewInit, OnDestro
233
238
  private setToolbarClass;
234
239
  private setSizingClass;
235
240
  static ɵfac: i0.ɵɵFactoryDeclaration<ListBoxComponent, never>;
236
- static ɵcmp: i0.ɵɵComponentDeclaration<ListBoxComponent, "kendo-listbox", never, { "textField": { "alias": "textField"; "required": false; }; "selectable": { "alias": "selectable"; "required": false; }; "data": { "alias": "data"; "required": false; }; "size": { "alias": "size"; "required": false; }; "toolbar": { "alias": "toolbar"; "required": false; }; "listboxLabel": { "alias": "listboxLabel"; "required": false; }; "listboxToolbarLabel": { "alias": "listboxToolbarLabel"; "required": false; }; "itemDisabled": { "alias": "itemDisabled"; "required": false; }; }, { "selectionChange": "selectionChange"; "action": "action"; "getChildListbox": "getChildListbox"; }, ["itemTemplate"], never, true, never>;
241
+ static ɵcmp: i0.ɵɵComponentDeclaration<ListBoxComponent, "kendo-listbox", never, { "textField": { "alias": "textField"; "required": false; }; "selectable": { "alias": "selectable"; "required": false; }; "data": { "alias": "data"; "required": false; }; "size": { "alias": "size"; "required": false; }; "toolbar": { "alias": "toolbar"; "required": false; }; "listboxLabel": { "alias": "listboxLabel"; "required": false; }; "listboxToolbarLabel": { "alias": "listboxToolbarLabel"; "required": false; }; "itemDisabled": { "alias": "itemDisabled"; "required": false; }; }, { "selectionChange": "selectionChange"; "action": "action"; "getChildListbox": "getChildListbox"; }, ["itemTemplate", "noDataTemplate"], never, true, never>;
237
242
  }
@@ -6,13 +6,14 @@ import * as i0 from "@angular/core";
6
6
  import * as i1 from "./listbox.component";
7
7
  import * as i2 from "./item-template.directive";
8
8
  import * as i3 from "./item-selectable.directive";
9
- import * as i4 from "./data-binding.directive";
10
- import * as i5 from "./localization/custom-messages.component";
9
+ import * as i4 from "./no-data-template.directive";
10
+ import * as i5 from "./data-binding.directive";
11
+ import * as i6 from "./localization/custom-messages.component";
11
12
  /**
12
13
  * Represents the [NgModule](https://angular.io/api/core/NgModule) definition for the ListBox component.
13
14
  */
14
15
  export declare class ListBoxModule {
15
16
  static ɵfac: i0.ɵɵFactoryDeclaration<ListBoxModule, never>;
16
- static ɵmod: i0.ɵɵNgModuleDeclaration<ListBoxModule, never, [typeof i1.ListBoxComponent, typeof i2.ItemTemplateDirective, typeof i3.ItemSelectableDirective, typeof i4.DataBindingDirective, typeof i5.CustomMessagesComponent], [typeof i1.ListBoxComponent, typeof i2.ItemTemplateDirective, typeof i3.ItemSelectableDirective, typeof i4.DataBindingDirective, typeof i5.CustomMessagesComponent]>;
17
+ static ɵmod: i0.ɵɵNgModuleDeclaration<ListBoxModule, never, [typeof i1.ListBoxComponent, typeof i2.ItemTemplateDirective, typeof i3.ItemSelectableDirective, typeof i4.NoDataTemplateDirective, typeof i5.DataBindingDirective, typeof i6.CustomMessagesComponent], [typeof i1.ListBoxComponent, typeof i2.ItemTemplateDirective, typeof i3.ItemSelectableDirective, typeof i4.NoDataTemplateDirective, typeof i5.DataBindingDirective, typeof i6.CustomMessagesComponent]>;
17
18
  static ɵinj: i0.ɵɵInjectorDeclaration<ListBoxModule>;
18
19
  }
@@ -0,0 +1,27 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { TemplateRef } from '@angular/core';
6
+ import * as i0 from "@angular/core";
7
+ /**
8
+ * Lets you customize the content shown when the ListBox has no data to display.
9
+ * To define a no-data template, nest an `<ng-template>` tag
10
+ * with the `kendoListBoxNoDataTemplate` directive inside the `<kendo-listbox>` tag
11
+ * ([see example](https://www.telerik.com/kendo-angular-ui/components/listbox/templates#no-data-template)).
12
+ *
13
+ * @example
14
+ * ```html
15
+ * <kendo-listbox [data]="[]">
16
+ * <ng-template kendoListBoxNoDataTemplate>
17
+ * No items to display.
18
+ * </ng-template>
19
+ * </kendo-listbox>
20
+ * ```
21
+ */
22
+ export declare class NoDataTemplateDirective {
23
+ templateRef: TemplateRef<any>;
24
+ constructor(templateRef: TemplateRef<any>);
25
+ static ɵfac: i0.ɵɵFactoryDeclaration<NoDataTemplateDirective, never>;
26
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NoDataTemplateDirective, "[kendoListBoxNoDataTemplate]", never, {}, {}, never, never, true, never>;
27
+ }
@@ -7,7 +7,7 @@ export const packageMetadata = {
7
7
  "productCodes": [
8
8
  "KENDOUIANGULAR"
9
9
  ],
10
- "publishDate": 1777363315,
11
- "version": "24.0.0-develop.8",
10
+ "publishDate": 1779273575,
11
+ "version": "24.0.0",
12
12
  "licensingDocsUrl": "https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning"
13
13
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@progress/kendo-angular-listbox",
3
- "version": "24.0.0-develop.8",
3
+ "version": "24.0.0",
4
4
  "description": "Kendo UI for Angular ListBox",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Progress",
@@ -41,7 +41,7 @@
41
41
  "package": {
42
42
  "productName": "Kendo UI for Angular",
43
43
  "productCode": "KENDOUIANGULAR",
44
- "publishDate": 1777363315,
44
+ "publishDate": 1779273575,
45
45
  "licensingDocsUrl": "https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning"
46
46
  }
47
47
  },
@@ -51,14 +51,14 @@
51
51
  "@angular/core": "19 - 21",
52
52
  "@angular/platform-browser": "19 - 21",
53
53
  "@progress/kendo-licensing": "^1.11.0",
54
- "@progress/kendo-angular-buttons": "24.0.0-develop.8",
55
- "@progress/kendo-angular-common": "24.0.0-develop.8",
56
- "@progress/kendo-angular-popup": "24.0.0-develop.8",
54
+ "@progress/kendo-angular-buttons": "24.0.0",
55
+ "@progress/kendo-angular-common": "24.0.0",
56
+ "@progress/kendo-angular-popup": "24.0.0",
57
57
  "rxjs": "^6.5.3 || ^7.0.0"
58
58
  },
59
59
  "dependencies": {
60
60
  "tslib": "^2.3.1",
61
- "@progress/kendo-angular-schematics": "24.0.0-develop.8",
61
+ "@progress/kendo-angular-schematics": "24.0.0",
62
62
  "@progress/kendo-common": "^1.0.1"
63
63
  },
64
64
  "schematics": "./schematics/collection.json",
@@ -11,11 +11,11 @@ function default_1(options) {
11
11
  // Additional dependencies to install.
12
12
  // See https://github.com/telerik/kendo-schematics/issues/28
13
13
  peerDependencies: {
14
- '@progress/kendo-angular-buttons': '24.0.0-develop.8',
15
- '@progress/kendo-angular-common': '24.0.0-develop.8',
16
- '@progress/kendo-angular-l10n': '24.0.0-develop.8',
14
+ '@progress/kendo-angular-buttons': '24.0.0',
15
+ '@progress/kendo-angular-common': '24.0.0',
16
+ '@progress/kendo-angular-l10n': '24.0.0',
17
17
  // Peer of kendo-angular-buttons
18
- '@progress/kendo-angular-popup': '24.0.0-develop.8'
18
+ '@progress/kendo-angular-popup': '24.0.0'
19
19
  } });
20
20
  return (0, schematics_1.externalSchematic)('@progress/kendo-angular-schematics', 'ng-add', finalOptions);
21
21
  }