@akcelik/strct 5.21.0 → 5.23.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.
@@ -2299,6 +2299,7 @@ class StrctRail {
2299
2299
  class="strct-rail__item"
2300
2300
  [routerLink]="item.routerLink"
2301
2301
  routerLinkActive
2302
+ ariaCurrentWhenActive="page"
2302
2303
  #rla="routerLinkActive"
2303
2304
  [class.strct-rail__item--active]="isActive(item, rla.isActive)"
2304
2305
  [attr.aria-current]="isActive(item, rla.isActive) ? 'page' : null"
@@ -2402,6 +2403,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
2402
2403
  class="strct-rail__item"
2403
2404
  [routerLink]="item.routerLink"
2404
2405
  routerLinkActive
2406
+ ariaCurrentWhenActive="page"
2405
2407
  #rla="routerLinkActive"
2406
2408
  [class.strct-rail__item--active]="isActive(item, rla.isActive)"
2407
2409
  [attr.aria-current]="isActive(item, rla.isActive) ? 'page' : null"
@@ -5276,6 +5278,9 @@ class StrctTreeNode {
5276
5278
  /** Roving tabindex: inside a tree only the active row is tabbable. */
5277
5279
  rowTabindex = computed(() => this.tree ? (this.tree.isRovingActive(this) ? 0 : -1) : 0, /* @ts-ignore */
5278
5280
  ...(ngDevMode ? [{ debugName: "rowTabindex" }] : /* istanbul ignore next */ []));
5281
+ /** Wording of the "children are being read" row (from the owning tree). */
5282
+ loadingLabel = computed(() => this.tree?.loadingLabel() ?? 'Loading…', /* @ts-ignore */
5283
+ ...(ngDevMode ? [{ debugName: "loadingLabel" }] : /* istanbul ignore next */ []));
5279
5284
  /** Accessible label of the chevron toggle (factory from the owning tree). */
5280
5285
  chevronAriaLabel = computed(() => (this.tree?.chevronAriaLabel() ?? defaultChevronAriaLabel)(this.isOpen(), this.displayLabel()), /* @ts-ignore */
5281
5286
  ...(ngDevMode ? [{ debugName: "chevronAriaLabel" }] : /* istanbul ignore next */ []));
@@ -5305,7 +5310,13 @@ class StrctTreeNode {
5305
5310
  }
5306
5311
  hasChildren = computed(() => {
5307
5312
  const n = this.node();
5308
- return n ? (n.children?.length ?? 0) > 0 : this.childNodes().length > 0;
5313
+ if (!n)
5314
+ return this.childNodes().length > 0;
5315
+ // A folder whose listing has not been asked for still opens: without
5316
+ // this it had no chevron and no aria-expanded, so it could not be.
5317
+ if (n.hasChildren !== undefined)
5318
+ return n.hasChildren || (n.children?.length ?? 0) > 0;
5319
+ return (n.children?.length ?? 0) > 0;
5309
5320
  }, /* @ts-ignore */
5310
5321
  ...(ngDevMode ? [{ debugName: "hasChildren" }] : /* istanbul ignore next */ []));
5311
5322
  isOpen = computed(() => {
@@ -5357,6 +5368,7 @@ class StrctTreeNode {
5357
5368
  [attr.aria-posinset]="posInSet()"
5358
5369
  [attr.aria-selected]="displayActive()"
5359
5370
  [attr.aria-expanded]="hasChildren() ? isOpen() : null"
5371
+ [attr.aria-busy]="node()?.loading ? true : null"
5360
5372
  [attr.aria-owns]="hasChildren() && isOpen() ? groupId : null"
5361
5373
  [attr.draggable]="isDraggable() ? 'true' : null"
5362
5374
  [class.strct-tnode__row--dragging]="isDragSource()"
@@ -5401,10 +5413,24 @@ class StrctTreeNode {
5401
5413
  />
5402
5414
  }
5403
5415
  <span class="strct-tnode__label">{{ displayLabel() }}</span>
5416
+ @if (node()?.tag; as tag) {
5417
+ <strct-badge class="strct-tnode__tag" [status]="tag.status ?? 'neutral'">{{
5418
+ tag.label
5419
+ }}</strct-badge>
5420
+ }
5421
+ @if (node()?.meta; as meta) {
5422
+ <span class="strct-tnode__meta">{{ meta }}</span>
5423
+ }
5404
5424
  <ng-content select="[strctTreeTrailing]" />
5405
5425
  </div>
5406
5426
  @if (hasChildren() && isOpen()) {
5407
5427
  <div class="strct-tnode__children" role="group" [id]="groupId">
5428
+ @if (node()?.loading) {
5429
+ <div class="strct-tnode__loading">
5430
+ <span class="strct-tnode__spacer"></span>
5431
+ <strct-spinner size="sm" [caption]="loadingLabel()" />
5432
+ </div>
5433
+ }
5408
5434
  @if (node()) {
5409
5435
  @for (child of node()!.children ?? []; track child.id ?? child.label) {
5410
5436
  <strct-tree-node
@@ -5419,11 +5445,11 @@ class StrctTreeNode {
5419
5445
  }
5420
5446
  </div>
5421
5447
  }
5422
- `, isInline: true, styles: [".strct-tnode{display:block}.strct-tnode__row{display:flex;align-items:center;gap:6px;padding:4px 9px;border-radius:2px;cursor:pointer;font-size:13px;color:var(--t1);-webkit-user-select:none;user-select:none}.strct-tnode__row:hover{background:var(--bg-3)}.strct-tnode__row--dragging{opacity:.45}.strct-tnode__row--droptarget,.strct-tnode__row--droptarget:hover{background:var(--acc-s);outline:1px solid var(--acc);outline-offset:-1px}.strct-tnode__row:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--acc50)}.strct-tnode__row--active{background:var(--acc-m);color:var(--t1);font-weight:600}.strct-tnode__row--active .strct-tnode__icon,.strct-tnode__row--active .strct-tnode__chevron{color:var(--acc)}.strct-tnode__chevron{display:inline-flex;align-items:center;justify-content:center;color:var(--t3);transition:transform .15s ease;width:24px;height:24px;margin:-5px;margin-inline-end:-10px;flex-shrink:0}.strct-tnode__chevron--open{transform:rotate(90deg)}[dir=rtl] .strct-tnode__chevron:not(.strct-tnode__chevron--open){transform:rotate(180deg)}.strct-tnode__spacer{width:14px;flex-shrink:0}@media(prefers-reduced-motion:reduce){.strct-tnode__chevron{transition:none}}.strct-tnode__icon{color:var(--t2);flex-shrink:0}.strct-tnode__label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-tnode__children{margin-inline-start:16px}\n"], dependencies: [{ kind: "component", type: StrctTreeNode, selector: "strct-tree-node", inputs: ["node", "label", "icon", "badge", "active", "expanded", "nodeMenu"], outputs: ["expandedChange", "activated", "nodeActivated", "nodeMenuSelect"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }, { kind: "directive", type: StrctContextMenuTrigger, selector: "[strctContextMenu]", inputs: ["strctContextMenu", "strctContextMenuData"], outputs: ["menuSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5448
+ `, isInline: true, styles: [".strct-tnode{display:block}.strct-tnode__row{display:flex;align-items:center;gap:6px;padding:4px 9px;border-radius:2px;cursor:pointer;font-size:13px;color:var(--t1);-webkit-user-select:none;user-select:none}.strct-tnode__row:hover{background:var(--bg-3)}.strct-tnode__row--dragging{opacity:.45}.strct-tnode__row--droptarget,.strct-tnode__row--droptarget:hover{background:var(--acc-s);outline:1px solid var(--acc);outline-offset:-1px}.strct-tnode__row:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--acc50)}.strct-tnode__row--active{background:var(--acc-m);color:var(--t1);font-weight:600}.strct-tnode__row--active .strct-tnode__icon,.strct-tnode__row--active .strct-tnode__chevron{color:var(--acc)}.strct-tnode__chevron{display:inline-flex;align-items:center;justify-content:center;color:var(--t3);transition:transform .15s ease;width:24px;height:24px;margin:-5px;margin-inline-end:-10px;flex-shrink:0}.strct-tnode__chevron--open{transform:rotate(90deg)}[dir=rtl] .strct-tnode__chevron:not(.strct-tnode__chevron--open){transform:rotate(180deg)}.strct-tnode__spacer{width:14px;flex-shrink:0}@media(prefers-reduced-motion:reduce){.strct-tnode__chevron{transition:none}}.strct-tnode__icon{color:var(--t2);flex-shrink:0}.strct-tnode__label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-tnode__tag,.strct-tnode__meta{flex-shrink:0}.strct-tnode__meta{font-size:11px;color:var(--t3);font-variant-numeric:tabular-nums}.strct-tnode__row--active .strct-tnode__meta{font-weight:400}.strct-tnode__children{margin-inline-start:16px}.strct-tnode__loading{display:flex;align-items:center;gap:6px;padding:4px 9px;font-size:13px;color:var(--t3)}\n"], dependencies: [{ kind: "component", type: StrctTreeNode, selector: "strct-tree-node", inputs: ["node", "label", "icon", "badge", "active", "expanded", "nodeMenu"], outputs: ["expandedChange", "activated", "nodeActivated", "nodeMenuSelect"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }, { kind: "directive", type: StrctContextMenuTrigger, selector: "[strctContextMenu]", inputs: ["strctContextMenu", "strctContextMenuData"], outputs: ["menuSelect"] }, { kind: "component", type: StrctBadge, selector: "strct-badge", inputs: ["status", "tone", "solid"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label", "caption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5423
5449
  }
5424
5450
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctTreeNode, decorators: [{
5425
5451
  type: Component,
5426
- args: [{ selector: 'strct-tree-node', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon, StrctContextMenuTrigger], template: `
5452
+ args: [{ selector: 'strct-tree-node', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon, StrctContextMenuTrigger, StrctBadge, StrctSpinner], template: `
5427
5453
  <div
5428
5454
  class="strct-tnode__row"
5429
5455
  [class.strct-tnode__row--active]="displayActive()"
@@ -5434,6 +5460,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
5434
5460
  [attr.aria-posinset]="posInSet()"
5435
5461
  [attr.aria-selected]="displayActive()"
5436
5462
  [attr.aria-expanded]="hasChildren() ? isOpen() : null"
5463
+ [attr.aria-busy]="node()?.loading ? true : null"
5437
5464
  [attr.aria-owns]="hasChildren() && isOpen() ? groupId : null"
5438
5465
  [attr.draggable]="isDraggable() ? 'true' : null"
5439
5466
  [class.strct-tnode__row--dragging]="isDragSource()"
@@ -5478,10 +5505,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
5478
5505
  />
5479
5506
  }
5480
5507
  <span class="strct-tnode__label">{{ displayLabel() }}</span>
5508
+ @if (node()?.tag; as tag) {
5509
+ <strct-badge class="strct-tnode__tag" [status]="tag.status ?? 'neutral'">{{
5510
+ tag.label
5511
+ }}</strct-badge>
5512
+ }
5513
+ @if (node()?.meta; as meta) {
5514
+ <span class="strct-tnode__meta">{{ meta }}</span>
5515
+ }
5481
5516
  <ng-content select="[strctTreeTrailing]" />
5482
5517
  </div>
5483
5518
  @if (hasChildren() && isOpen()) {
5484
5519
  <div class="strct-tnode__children" role="group" [id]="groupId">
5520
+ @if (node()?.loading) {
5521
+ <div class="strct-tnode__loading">
5522
+ <span class="strct-tnode__spacer"></span>
5523
+ <strct-spinner size="sm" [caption]="loadingLabel()" />
5524
+ </div>
5525
+ }
5485
5526
  @if (node()) {
5486
5527
  @for (child of node()!.children ?? []; track child.id ?? child.label) {
5487
5528
  <strct-tree-node
@@ -5502,7 +5543,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
5502
5543
  // siblings in the DOM, so the host must not appear in the a11y tree.
5503
5544
  role: 'none',
5504
5545
  '[attr.data-node-id]': 'node()?.id ?? null',
5505
- }, styles: [".strct-tnode{display:block}.strct-tnode__row{display:flex;align-items:center;gap:6px;padding:4px 9px;border-radius:2px;cursor:pointer;font-size:13px;color:var(--t1);-webkit-user-select:none;user-select:none}.strct-tnode__row:hover{background:var(--bg-3)}.strct-tnode__row--dragging{opacity:.45}.strct-tnode__row--droptarget,.strct-tnode__row--droptarget:hover{background:var(--acc-s);outline:1px solid var(--acc);outline-offset:-1px}.strct-tnode__row:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--acc50)}.strct-tnode__row--active{background:var(--acc-m);color:var(--t1);font-weight:600}.strct-tnode__row--active .strct-tnode__icon,.strct-tnode__row--active .strct-tnode__chevron{color:var(--acc)}.strct-tnode__chevron{display:inline-flex;align-items:center;justify-content:center;color:var(--t3);transition:transform .15s ease;width:24px;height:24px;margin:-5px;margin-inline-end:-10px;flex-shrink:0}.strct-tnode__chevron--open{transform:rotate(90deg)}[dir=rtl] .strct-tnode__chevron:not(.strct-tnode__chevron--open){transform:rotate(180deg)}.strct-tnode__spacer{width:14px;flex-shrink:0}@media(prefers-reduced-motion:reduce){.strct-tnode__chevron{transition:none}}.strct-tnode__icon{color:var(--t2);flex-shrink:0}.strct-tnode__label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-tnode__children{margin-inline-start:16px}\n"] }]
5546
+ }, styles: [".strct-tnode{display:block}.strct-tnode__row{display:flex;align-items:center;gap:6px;padding:4px 9px;border-radius:2px;cursor:pointer;font-size:13px;color:var(--t1);-webkit-user-select:none;user-select:none}.strct-tnode__row:hover{background:var(--bg-3)}.strct-tnode__row--dragging{opacity:.45}.strct-tnode__row--droptarget,.strct-tnode__row--droptarget:hover{background:var(--acc-s);outline:1px solid var(--acc);outline-offset:-1px}.strct-tnode__row:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--acc50)}.strct-tnode__row--active{background:var(--acc-m);color:var(--t1);font-weight:600}.strct-tnode__row--active .strct-tnode__icon,.strct-tnode__row--active .strct-tnode__chevron{color:var(--acc)}.strct-tnode__chevron{display:inline-flex;align-items:center;justify-content:center;color:var(--t3);transition:transform .15s ease;width:24px;height:24px;margin:-5px;margin-inline-end:-10px;flex-shrink:0}.strct-tnode__chevron--open{transform:rotate(90deg)}[dir=rtl] .strct-tnode__chevron:not(.strct-tnode__chevron--open){transform:rotate(180deg)}.strct-tnode__spacer{width:14px;flex-shrink:0}@media(prefers-reduced-motion:reduce){.strct-tnode__chevron{transition:none}}.strct-tnode__icon{color:var(--t2);flex-shrink:0}.strct-tnode__label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-tnode__tag,.strct-tnode__meta{flex-shrink:0}.strct-tnode__meta{font-size:11px;color:var(--t3);font-variant-numeric:tabular-nums}.strct-tnode__row--active .strct-tnode__meta{font-weight:400}.strct-tnode__children{margin-inline-start:16px}.strct-tnode__loading{display:flex;align-items:center;gap:6px;padding:4px 9px;font-size:13px;color:var(--t3)}\n"] }]
5506
5547
  }], ctorParameters: () => [], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], nodeMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeMenu", required: false }] }], activated: [{ type: i0.Output, args: ["activated"] }], nodeActivated: [{ type: i0.Output, args: ["nodeActivated"] }], nodeMenuSelect: [{ type: i0.Output, args: ["nodeMenuSelect"] }], childNodes: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctTreeNode), { isSignal: true }] }], directChildNodes: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctTreeNode), { ...{ descendants: false }, isSignal: true }] }] } });
5507
5548
  /**
5508
5549
  * Root container for a tree. Either project `<strct-tree-node>` children, or
@@ -5551,6 +5592,9 @@ class StrctTree {
5551
5592
  ...(ngDevMode ? [{ debugName: "dragExpandDelay" }] : /* istanbul ignore next */ []));
5552
5593
  /** Emitted for an accepted drop only. */
5553
5594
  nodeDrop = output();
5595
+ /** Wording of the row shown under a node whose children are being read (`node.loading`). */
5596
+ loadingLabel = input('Loading…', /* @ts-ignore */
5597
+ ...(ngDevMode ? [{ debugName: "loadingLabel" }] : /* istanbul ignore next */ []));
5554
5598
  /** Accessible label of each node's chevron toggle; receives the expanded state and the node label. */
5555
5599
  chevronAriaLabel = input(defaultChevronAriaLabel, /* @ts-ignore */
5556
5600
  ...(ngDevMode ? [{ debugName: "chevronAriaLabel" }] : /* istanbul ignore next */ []));
@@ -5893,7 +5937,7 @@ class StrctTree {
5893
5937
  this.expandedChange.emit([...this.currentSet()]);
5894
5938
  }
5895
5939
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctTree, deps: [], target: i0.ɵɵFactoryTarget.Component });
5896
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctTree, isStandalone: true, selector: "strct-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null }, framed: { classPropertyName: "framed", publicName: "framed", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, nodeMenu: { classPropertyName: "nodeMenu", publicName: "nodeMenu", isSignal: true, isRequired: false, transformFunction: null }, canDrag: { classPropertyName: "canDrag", publicName: "canDrag", isSignal: true, isRequired: false, transformFunction: null }, canDrop: { classPropertyName: "canDrop", publicName: "canDrop", isSignal: true, isRequired: false, transformFunction: null }, dragExpandDelay: { classPropertyName: "dragExpandDelay", publicName: "dragExpandDelay", isSignal: true, isRequired: false, transformFunction: null }, chevronAriaLabel: { classPropertyName: "chevronAriaLabel", publicName: "chevronAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, expandedIds: { classPropertyName: "expandedIds", publicName: "expandedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeDrop: "nodeDrop", nodeActivated: "nodeActivated", nodeMenuSelect: "nodeMenuSelect", expandedIds: "expandedIdsChange", expandedChange: "expandedChange", nodeToggled: "nodeToggled" }, host: { attributes: { "role": "tree" }, properties: { "class.strct-tree--comfortable": "density() === 'comfortable'", "class.strct-tree--framed": "framed()", "style.max-height.px": "maxHeight()" }, classAttribute: "strct-tree" }, queries: [{ propertyName: "projectedNodes", predicate: StrctTreeNode, isSignal: true }], ngImport: i0, template: `
5940
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctTree, isStandalone: true, selector: "strct-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null }, framed: { classPropertyName: "framed", publicName: "framed", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, nodeMenu: { classPropertyName: "nodeMenu", publicName: "nodeMenu", isSignal: true, isRequired: false, transformFunction: null }, canDrag: { classPropertyName: "canDrag", publicName: "canDrag", isSignal: true, isRequired: false, transformFunction: null }, canDrop: { classPropertyName: "canDrop", publicName: "canDrop", isSignal: true, isRequired: false, transformFunction: null }, dragExpandDelay: { classPropertyName: "dragExpandDelay", publicName: "dragExpandDelay", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null }, chevronAriaLabel: { classPropertyName: "chevronAriaLabel", publicName: "chevronAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, expandedIds: { classPropertyName: "expandedIds", publicName: "expandedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeDrop: "nodeDrop", nodeActivated: "nodeActivated", nodeMenuSelect: "nodeMenuSelect", expandedIds: "expandedIdsChange", expandedChange: "expandedChange", nodeToggled: "nodeToggled" }, host: { attributes: { "role": "tree" }, properties: { "class.strct-tree--comfortable": "density() === 'comfortable'", "class.strct-tree--framed": "framed()", "style.max-height.px": "maxHeight()" }, classAttribute: "strct-tree" }, queries: [{ propertyName: "projectedNodes", predicate: StrctTreeNode, isSignal: true }], ngImport: i0, template: `
5897
5941
  @if (nodes(); as ns) {
5898
5942
  @for (n of ns; track n.id ?? n.label) {
5899
5943
  <strct-tree-node
@@ -5930,7 +5974,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
5930
5974
  '[class.strct-tree--framed]': 'framed()',
5931
5975
  '[style.max-height.px]': 'maxHeight()',
5932
5976
  }, styles: [".strct-tree{display:block}.strct-tree--framed{border:1px solid var(--b2);border-radius:var(--radius-md);background:var(--bg-1);padding:var(--space-1)}.strct-tree[style*=max-height]{overflow:auto}.strct-tree--comfortable .strct-tnode__row{gap:7px;padding:6px 10px;border-radius:3px;font-size:14px}.strct-tree--comfortable .strct-tnode__chevron{margin:-4px;margin-inline-end:-9px}.strct-tree--comfortable .strct-tnode__spacer{width:16px}.strct-tree--comfortable .strct-tnode__children{margin-inline-start:19px}\n"] }]
5933
- }], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], density: [{ type: i0.Input, args: [{ isSignal: true, alias: "density", required: false }] }], framed: [{ type: i0.Input, args: [{ isSignal: true, alias: "framed", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], nodeMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeMenu", required: false }] }], canDrag: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDrag", required: false }] }], canDrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDrop", required: false }] }], dragExpandDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragExpandDelay", required: false }] }], nodeDrop: [{ type: i0.Output, args: ["nodeDrop"] }], chevronAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "chevronAriaLabel", required: false }] }], nodeActivated: [{ type: i0.Output, args: ["nodeActivated"] }], nodeMenuSelect: [{ type: i0.Output, args: ["nodeMenuSelect"] }], expandedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIds", required: false }] }, { type: i0.Output, args: ["expandedIdsChange"] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }], nodeToggled: [{ type: i0.Output, args: ["nodeToggled"] }], projectedNodes: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctTreeNode), { ...{ descendants: false }, isSignal: true }] }] } });
5977
+ }], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], density: [{ type: i0.Input, args: [{ isSignal: true, alias: "density", required: false }] }], framed: [{ type: i0.Input, args: [{ isSignal: true, alias: "framed", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], nodeMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeMenu", required: false }] }], canDrag: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDrag", required: false }] }], canDrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDrop", required: false }] }], dragExpandDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragExpandDelay", required: false }] }], nodeDrop: [{ type: i0.Output, args: ["nodeDrop"] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }], chevronAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "chevronAriaLabel", required: false }] }], nodeActivated: [{ type: i0.Output, args: ["nodeActivated"] }], nodeMenuSelect: [{ type: i0.Output, args: ["nodeMenuSelect"] }], expandedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIds", required: false }] }, { type: i0.Output, args: ["expandedIdsChange"] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }], nodeToggled: [{ type: i0.Output, args: ["nodeToggled"] }], projectedNodes: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctTreeNode), { ...{ descendants: false }, isSignal: true }] }] } });
5934
5978
 
5935
5979
  /**
5936
5980
  * Refcounted body scroll-lock shared across any number of simultaneously
@@ -6123,10 +6167,25 @@ class StrctModal {
6123
6167
  this.close();
6124
6168
  }
6125
6169
  onEscape(event) {
6126
- // A control that used Escape first keeps it: an IME composition, a
6127
- // searchbox that clears. Both mark the event handled.
6170
+ // A control that used Escape first keeps it: a searchbox that clears
6171
+ // marks the event handled (it did not, until 5.23.0).
6128
6172
  if (event?.defaultPrevented)
6129
6173
  return;
6174
+ // An IME composition ends on Escape, and the keystroke is the composer's.
6175
+ if (event?.isComposing)
6176
+ return;
6177
+ // An Escape raised inside another surface on top — a command palette
6178
+ // opened over this modal, a menu, a listbox — belongs to that surface.
6179
+ // isTopmostModal only knows about modals, so the palette's Escape used to
6180
+ // close the palette AND the modal. An Escape with the focus on nothing in
6181
+ // particular is still ours.
6182
+ const target = event?.target;
6183
+ const surface = target instanceof Element
6184
+ ? target.closest('[role="dialog"], [role="menu"], [role="listbox"], [role="tree"]')
6185
+ : null;
6186
+ const dialog = this.elementRef.nativeElement.querySelector('.strct-modal__dialog');
6187
+ if (surface && dialog && surface !== dialog && !dialog.contains(surface))
6188
+ return;
6130
6189
  // With several modals open, only the topmost one reacts to Escape.
6131
6190
  const allowed = this.closeOnEscape() ?? this.dismissible();
6132
6191
  if (this.open() && allowed && isTopmostModal(this))
@@ -7736,6 +7795,7 @@ class StrctSectionMenu {
7736
7795
  class="strct-sm__item"
7737
7796
  [routerLink]="item.routerLink"
7738
7797
  routerLinkActive
7798
+ ariaCurrentWhenActive="page"
7739
7799
  #rla="routerLinkActive"
7740
7800
  [class.strct-sm__item--active]="isActive(item, rla.isActive)"
7741
7801
  [attr.aria-current]="isActive(item, rla.isActive) ? 'page' : null"
@@ -7846,6 +7906,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
7846
7906
  class="strct-sm__item"
7847
7907
  [routerLink]="item.routerLink"
7848
7908
  routerLinkActive
7909
+ ariaCurrentWhenActive="page"
7849
7910
  #rla="routerLinkActive"
7850
7911
  [class.strct-sm__item--active]="isActive(item, rla.isActive)"
7851
7912
  [attr.aria-current]="isActive(item, rla.isActive) ? 'page' : null"
@@ -8402,6 +8463,16 @@ class StrctSearchbox {
8402
8463
  this.onChange(next);
8403
8464
  }
8404
8465
  /** Clear the text (Escape / the × button). */
8466
+ /**
8467
+ * An Escape that clears a value is used: a modal around this box takes an
8468
+ * unhandled Escape as "close me", and the same keystroke did both.
8469
+ */
8470
+ onEscape(event) {
8471
+ if (!this.value())
8472
+ return;
8473
+ event.preventDefault();
8474
+ this.clear();
8475
+ }
8405
8476
  clear() {
8406
8477
  if (!this.value())
8407
8478
  return;
@@ -8456,7 +8527,7 @@ class StrctSearchbox {
8456
8527
  [value]="value()"
8457
8528
  (input)="onInput($event)"
8458
8529
  (keydown.enter)="search.emit(value())"
8459
- (keydown.escape)="clear()"
8530
+ (keydown.escape)="onEscape($event)"
8460
8531
  (focus)="focused.set(true)"
8461
8532
  (blur)="focused.set(false); onTouched()"
8462
8533
  />
@@ -8509,7 +8580,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
8509
8580
  [value]="value()"
8510
8581
  (input)="onInput($event)"
8511
8582
  (keydown.enter)="search.emit(value())"
8512
- (keydown.escape)="clear()"
8583
+ (keydown.escape)="onEscape($event)"
8513
8584
  (focus)="focused.set(true)"
8514
8585
  (blur)="focused.set(false); onTouched()"
8515
8586
  />
@@ -28428,7 +28499,7 @@ class StrctTreeSelect {
28428
28499
  }
28429
28500
  </div>
28430
28501
  }
28431
- `, isInline: true, styles: [".strct-tsel{position:relative;display:block;width:100%}.strct-tsel__field{position:relative}.strct-tsel__trigger{display:flex;align-items:center;gap:8px;padding-inline-end:30px;text-align:start;cursor:pointer}.strct-tsel__trigger--clearable{padding-inline-end:48px}.strct-tsel__trigger:disabled{cursor:not-allowed}.strct-tsel__value{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-tsel__value--empty{color:var(--t3)}.strct-tsel__caret{position:absolute;inset-inline-end:9px;top:50%;transform:translateY(-50%);color:var(--t3);pointer-events:none}.strct-tsel__clear{position:absolute;inset-inline-end:26px;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;padding:2px;color:var(--t3);background:none;border:none;border-radius:var(--radius-sm);cursor:pointer}.strct-tsel__clear:hover{color:var(--t1)}.strct-tsel__panel{z-index:var(--z-dropdown);max-height:260px;overflow-y:auto;padding:var(--space-1);background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-lg);box-shadow:var(--shh)}.strct-tsel__empty{padding:9px 10px;font-size:13px;color:var(--t3)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }, { kind: "directive", type: StrctOverlay, selector: "[strctOverlay]", inputs: ["strctOverlay", "strctOverlayPlacement", "strctOverlayMatchWidth", "strctOverlayGap"] }, { kind: "component", type: StrctTree, selector: "strct-tree", inputs: ["nodes", "density", "framed", "maxHeight", "nodeMenu", "canDrag", "canDrop", "dragExpandDelay", "chevronAriaLabel", "expandedIds"], outputs: ["nodeDrop", "nodeActivated", "nodeMenuSelect", "expandedIdsChange", "expandedChange", "nodeToggled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
28502
+ `, isInline: true, styles: [".strct-tsel{position:relative;display:block;width:100%}.strct-tsel__field{position:relative}.strct-tsel__trigger{display:flex;align-items:center;gap:8px;padding-inline-end:30px;text-align:start;cursor:pointer}.strct-tsel__trigger--clearable{padding-inline-end:48px}.strct-tsel__trigger:disabled{cursor:not-allowed}.strct-tsel__value{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-tsel__value--empty{color:var(--t3)}.strct-tsel__caret{position:absolute;inset-inline-end:9px;top:50%;transform:translateY(-50%);color:var(--t3);pointer-events:none}.strct-tsel__clear{position:absolute;inset-inline-end:26px;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;padding:2px;color:var(--t3);background:none;border:none;border-radius:var(--radius-sm);cursor:pointer}.strct-tsel__clear:hover{color:var(--t1)}.strct-tsel__panel{z-index:var(--z-dropdown);max-height:260px;overflow-y:auto;padding:var(--space-1);background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-lg);box-shadow:var(--shh)}.strct-tsel__empty{padding:9px 10px;font-size:13px;color:var(--t3)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }, { kind: "directive", type: StrctOverlay, selector: "[strctOverlay]", inputs: ["strctOverlay", "strctOverlayPlacement", "strctOverlayMatchWidth", "strctOverlayGap"] }, { kind: "component", type: StrctTree, selector: "strct-tree", inputs: ["nodes", "density", "framed", "maxHeight", "nodeMenu", "canDrag", "canDrop", "dragExpandDelay", "loadingLabel", "chevronAriaLabel", "expandedIds"], outputs: ["nodeDrop", "nodeActivated", "nodeMenuSelect", "expandedIdsChange", "expandedChange", "nodeToggled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
28432
28503
  }
28433
28504
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctTreeSelect, decorators: [{
28434
28505
  type: Component,
@@ -28717,6 +28788,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
28717
28788
  type: Directive,
28718
28789
  args: [{ selector: '[strctToolbarCaption]' }]
28719
28790
  }] });
28791
+ /** A control whose own keyboard is the caret's. */
28792
+ function isTextEntry(el) {
28793
+ if (!el)
28794
+ return false;
28795
+ // `isContentEditable` is a rendering-time property: jsdom does not implement
28796
+ // it, so the attribute is read too — a consumer's own test sees the same
28797
+ // behaviour as a browser.
28798
+ if (el.isContentEditable)
28799
+ return true;
28800
+ const editable = el.closest('[contenteditable]')?.getAttribute('contenteditable');
28801
+ if (editable !== null && editable !== undefined && editable !== 'false')
28802
+ return true;
28803
+ const tag = el.tagName;
28804
+ if (tag === 'TEXTAREA')
28805
+ return true;
28806
+ if (tag !== 'INPUT')
28807
+ return false;
28808
+ const type = el.type;
28809
+ return !['button', 'submit', 'reset', 'checkbox', 'radio', 'range', 'color', 'file'].includes(type);
28810
+ }
28720
28811
  class StrctToolbar {
28721
28812
  host = inject(ElementRef);
28722
28813
  /** Accessible name of the toolbar (localizable). */
@@ -28753,6 +28844,11 @@ class StrctToolbar {
28753
28844
  const target = event.target;
28754
28845
  if (target?.closest('[role=listbox], [role=menu], [role=dialog], [role=tree], [role=grid]'))
28755
28846
  return;
28847
+ // A text field keeps its arrows for the caret — APG's toolbar says so, and
28848
+ // ArrowLeft inside a searchbox in the bar used to jump to the button
28849
+ // before it instead of moving one character.
28850
+ if (isTextEntry(target))
28851
+ return;
28756
28852
  const vertical = this.orientation() === 'vertical';
28757
28853
  const prevKey = vertical ? 'ArrowUp' : 'ArrowLeft';
28758
28854
  const nextKey = vertical ? 'ArrowDown' : 'ArrowRight';
@@ -29759,6 +29855,13 @@ const STRCT_MD_LIMITS = {
29759
29855
  depth: 8,
29760
29856
  /** Inline delimiter runs considered per text span. */
29761
29857
  delimiters: 2000,
29858
+ /**
29859
+ * How far a closing delimiter or bracket is looked for. Without it every
29860
+ * unmatched opener scanned to the end of the document, once each: a 64 KiB
29861
+ * line of "*a " took 1.6 s to read, and a streamed reply is read again on
29862
+ * every token.
29863
+ */
29864
+ scan: 4096,
29762
29865
  };
29763
29866
  const RULE = /^ {0,3}((\*\s*){3,}|(-\s*){3,}|(_\s*){3,})$/;
29764
29867
  const ATX = /^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/;
@@ -29996,9 +30099,10 @@ function parseInlines(source, options = {}) {
29996
30099
  continue;
29997
30100
  }
29998
30101
  }
29999
- // Hard break: two spaces at the end of a line, or a backslash.
30102
+ // Hard break: two spaces at the end of a line, or a backslash — or every
30103
+ // newline, where the consumer asked for GitHub's comment style.
30000
30104
  if (ch === '\n') {
30001
- const hard = buf.endsWith(' ') || buf.endsWith('\\');
30105
+ const hard = options.breaks === true || buf.endsWith(' ') || buf.endsWith('\\');
30002
30106
  buf = buf.replace(/( {2,}|\\)$/, '');
30003
30107
  flush();
30004
30108
  out.push(hard ? { kind: 'break' } : { kind: 'text', text: ' ' });
@@ -30040,13 +30144,39 @@ function parseInlines(source, options = {}) {
30040
30144
  }
30041
30145
  }
30042
30146
  }
30147
+ // A bare URL is a link: a model writes "see https://example.com/x" far
30148
+ // more often than it writes an autolink. Trailing punctuation belongs to
30149
+ // the sentence, not the address.
30150
+ if ((ch === 'h' || ch === 'H') && /^https?:\/\//i.test(source.slice(i, i + 8))) {
30151
+ const match = /^https?:\/\/[^\s<]+/i.exec(source.slice(i));
30152
+ if (match) {
30153
+ let url = match[0];
30154
+ const trail = /[.,;:!?)\]'"]+$/.exec(url);
30155
+ if (trail) {
30156
+ // A closing bracket is part of the address when the URL opened one.
30157
+ const kept = url.slice(0, url.length - trail[0].length);
30158
+ url = kept.includes('(') && trail[0].startsWith(')') ? kept + ')' : kept;
30159
+ }
30160
+ if (url.length > 'https://'.length) {
30161
+ flush();
30162
+ out.push({ kind: 'link', href: url, children: [{ kind: 'text', text: url }] });
30163
+ i += url.length;
30164
+ continue;
30165
+ }
30166
+ }
30167
+ }
30043
30168
  // Emphasis, strong, strikethrough. A delimiter only opens when something
30044
30169
  // follows it immediately and only closes when something precedes it —
30045
30170
  // the flanking rule, which is what keeps "2 * 3 * 4" arithmetic.
30046
30171
  if ((ch === '*' || ch === '_' || ch === '~') && budget-- > 0) {
30047
30172
  const run = new RegExp(`^\\${ch}+`).exec(source.slice(i))[0];
30048
30173
  const len = ch === '~' ? (run.length >= 2 ? 2 : 0) : Math.min(run.length, 2);
30049
- const opens = !/^\s|^$/.test(source.slice(i + run.length, i + run.length + 1) || '');
30174
+ const after = source.slice(i + run.length, i + run.length + 1) || '';
30175
+ const before = i > 0 ? source[i - 1] : '';
30176
+ // An underscore inside a word is a character, not a delimiter — or
30177
+ // `list_inventory for vm_cpu_usage` loses its underscores to emphasis.
30178
+ const intraword = ch === '_' && /[\p{L}\p{N}]/u.test(before) && /[\p{L}\p{N}]/u.test(after);
30179
+ const opens = !/^\s|^$/.test(after) && !intraword;
30050
30180
  if (len && opens) {
30051
30181
  const marker = ch.repeat(len);
30052
30182
  const close = findCloser(source, marker, i + len);
@@ -30075,10 +30205,15 @@ function parseInlines(source, options = {}) {
30075
30205
  * no such closer is not a delimiter at all, it is the character written.
30076
30206
  */
30077
30207
  function findCloser(source, marker, from) {
30208
+ // Bounded: an unmatched delimiter in a long reply used to scan to the end of
30209
+ // the document, once per delimiter — 1.6s for a 64 KiB line of "*a ".
30210
+ const limit = Math.min(source.length, from + STRCT_MD_LIMITS.scan);
30078
30211
  let at = source.indexOf(marker, from);
30079
- while (at !== -1) {
30212
+ while (at !== -1 && at < limit) {
30080
30213
  const before = source[at - 1];
30081
- if (before && !/\s/.test(before))
30214
+ const after = source[at + marker.length] ?? '';
30215
+ const intraword = marker[0] === '_' && /[\p{L}\p{N}]/u.test(before ?? '') && /[\p{L}\p{N}]/u.test(after);
30216
+ if (before && !/\s/.test(before) && !intraword)
30082
30217
  return at;
30083
30218
  at = source.indexOf(marker, at + marker.length);
30084
30219
  }
@@ -30087,7 +30222,8 @@ function findCloser(source, marker, from) {
30087
30222
  /** The index of the `]` matching the `[` at `from`, or -1. */
30088
30223
  function matchBracket(source, from) {
30089
30224
  let depth = 0;
30090
- for (let i = from; i < source.length; i++) {
30225
+ const limit = Math.min(source.length, from + STRCT_MD_LIMITS.scan);
30226
+ for (let i = from; i < limit; i++) {
30091
30227
  if (source[i] === '\\') {
30092
30228
  i++;
30093
30229
  continue;
@@ -30140,7 +30276,7 @@ function applyTokens(text, tokenize) {
30140
30276
  * model wrote: `javascript:`, `data:`, a protocol-relative `//host`, or
30141
30277
  * anything this does not recognise.
30142
30278
  */
30143
- function strctClassifyHref(href) {
30279
+ function strctClassifyHref(href, options = {}) {
30144
30280
  const raw = (href ?? '').trim();
30145
30281
  if (!raw)
30146
30282
  return null;
@@ -30149,10 +30285,16 @@ function strctClassifyHref(href) {
30149
30285
  return null;
30150
30286
  if (/^https?:\/\/[^/]/i.test(raw))
30151
30287
  return 'external';
30152
- if (/^mailto:[^@\s]+@[^@\s]+$/i.test(raw))
30288
+ // mailto: opens a mail client with a subject and a body the model wrote, so
30289
+ // it is something an app says yes to rather than the default.
30290
+ if (options.mailto && /^mailto:[^@\s]+@[^@\s]+$/i.test(raw))
30153
30291
  return 'external';
30154
30292
  if (raw.startsWith('//'))
30155
30293
  return null;
30294
+ // A browser reads a backslash as a slash: "/\evil.example" is an in-app
30295
+ // path to this function and https://evil.example/ to a middle-click.
30296
+ if (/[\\]/.test(raw) || /%5c/i.test(raw))
30297
+ return null;
30156
30298
  if (raw.startsWith('/'))
30157
30299
  return 'internal';
30158
30300
  return null;
@@ -30226,10 +30368,32 @@ class StrctMarkdown {
30226
30368
  /** Claim runs of plain text — an inventory id becomes an object chip. */
30227
30369
  tokens = input(null, /* @ts-ignore */
30228
30370
  ...(ngDevMode ? [{ debugName: "tokens" }] : /* istanbul ignore next */ []));
30371
+ /**
30372
+ * A single newline is a line break, the way a comment box reads: a model
30373
+ * writing "Host: X\nCPU: 40 %" means two lines. Off by default, which is
30374
+ * CommonMark.
30375
+ */
30376
+ breaks = input(false, { ...(ngDevMode ? { debugName: "breaks" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
30377
+ /** What a screen reader hears after an external link (localisable). */
30378
+ newTabLabel = input(' (opens in a new tab)', /* @ts-ignore */
30379
+ ...(ngDevMode ? [{ debugName: "newTabLabel" }] : /* istanbul ignore next */ []));
30380
+ /**
30381
+ * The token templates of the view that nested this one. A list item or a
30382
+ * quote is drawn by a nested view, which has no projected content of its
30383
+ * own — without this its claimed runs fall back to plain text.
30384
+ */
30385
+ inheritedTokens = input([], /* @ts-ignore */
30386
+ ...(ngDevMode ? [{ debugName: "inheritedTokens" }] : /* istanbul ignore next */ []));
30229
30387
  /** An in-app link was followed; the consumer routes it. */
30230
30388
  navigate = output();
30231
- tokenDefs = contentChildren(StrctMarkdownToken, /* @ts-ignore */
30232
- ...(ngDevMode ? [{ debugName: "tokenDefs" }] : /* istanbul ignore next */ []));
30389
+ ownTokenDefs = contentChildren(StrctMarkdownToken, /* @ts-ignore */
30390
+ ...(ngDevMode ? [{ debugName: "ownTokenDefs" }] : /* istanbul ignore next */ []));
30391
+ /** This view's own templates, plus the ones handed down to it. */
30392
+ allTokenDefs = computed(() => {
30393
+ const own = this.ownTokenDefs();
30394
+ return own.length ? own : this.inheritedTokens();
30395
+ }, /* @ts-ignore */
30396
+ ...(ngDevMode ? [{ debugName: "allTokenDefs" }] : /* istanbul ignore next */ []));
30233
30397
  blocks = computed(() => {
30234
30398
  const given = this.tree();
30235
30399
  if (given)
@@ -30237,6 +30401,7 @@ class StrctMarkdown {
30237
30401
  return strctParseMarkdown(this.source(), {
30238
30402
  streaming: this.streaming(),
30239
30403
  tokenize: this.tokens() ?? undefined,
30404
+ breaks: this.breaks(),
30240
30405
  });
30241
30406
  }, /* @ts-ignore */
30242
30407
  ...(ngDevMode ? [{ debugName: "blocks" }] : /* istanbul ignore next */ []));
@@ -30248,7 +30413,7 @@ class StrctMarkdown {
30248
30413
  return own ? own(href) : strctClassifyHref(href);
30249
30414
  }
30250
30415
  tokenTemplate(kind) {
30251
- return this.tokenDefs().find((d) => d.strctMarkdownToken() === kind)?.template ?? null;
30416
+ return this.allTokenDefs().find((d) => d.strctMarkdownToken() === kind)?.template ?? null;
30252
30417
  }
30253
30418
  /** The caret belongs to the last block, and only while streaming. */
30254
30419
  caretOn(index) {
@@ -30263,7 +30428,7 @@ class StrctMarkdown {
30263
30428
  this.navigate.emit(href);
30264
30429
  }
30265
30430
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctMarkdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
30266
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctMarkdown, isStandalone: true, selector: "strct-markdown", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, tree: { classPropertyName: "tree", publicName: "tree", isSignal: true, isRequired: false, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, headingOffset: { classPropertyName: "headingOffset", publicName: "headingOffset", isSignal: true, isRequired: false, transformFunction: null }, linkPolicy: { classPropertyName: "linkPolicy", publicName: "linkPolicy", isSignal: true, isRequired: false, transformFunction: null }, tokens: { classPropertyName: "tokens", publicName: "tokens", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { navigate: "navigate" }, host: { classAttribute: "strct-md" }, queries: [{ propertyName: "tokenDefs", predicate: StrctMarkdownToken, isSignal: true }], ngImport: i0, template: `
30431
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctMarkdown, isStandalone: true, selector: "strct-markdown", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, tree: { classPropertyName: "tree", publicName: "tree", isSignal: true, isRequired: false, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, headingOffset: { classPropertyName: "headingOffset", publicName: "headingOffset", isSignal: true, isRequired: false, transformFunction: null }, linkPolicy: { classPropertyName: "linkPolicy", publicName: "linkPolicy", isSignal: true, isRequired: false, transformFunction: null }, tokens: { classPropertyName: "tokens", publicName: "tokens", isSignal: true, isRequired: false, transformFunction: null }, breaks: { classPropertyName: "breaks", publicName: "breaks", isSignal: true, isRequired: false, transformFunction: null }, newTabLabel: { classPropertyName: "newTabLabel", publicName: "newTabLabel", isSignal: true, isRequired: false, transformFunction: null }, inheritedTokens: { classPropertyName: "inheritedTokens", publicName: "inheritedTokens", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { navigate: "navigate" }, host: { classAttribute: "strct-md" }, queries: [{ propertyName: "ownTokenDefs", predicate: StrctMarkdownToken, isSignal: true }], ngImport: i0, template: `
30267
30432
  @for (block of blocks(); track $index) {
30268
30433
  @switch (block.kind) {
30269
30434
  @case ('p') {
@@ -30408,10 +30573,16 @@ class StrctMarkdown {
30408
30573
  <!-- Blocks inside a list item or a quote. -->
30409
30574
  <ng-template #blockRun let-blocks>
30410
30575
  @for (b of blocks; track $index) {
30576
+ <!-- The nested view had no token templates of its own, so a claimed
30577
+ run inside a list item or a quote was drawn as plain text while
30578
+ the same run in a paragraph became a chip. -->
30411
30579
  <strct-markdown
30412
30580
  [tree]="[b]"
30413
30581
  [headingOffset]="headingOffset()"
30414
30582
  [linkPolicy]="linkPolicy()"
30583
+ [tokens]="tokens()"
30584
+ [breaks]="breaks()"
30585
+ [inheritedTokens]="allTokenDefs()"
30415
30586
  (navigate)="navigate.emit($event)"
30416
30587
  />
30417
30588
  }
@@ -30483,6 +30654,7 @@ class StrctMarkdown {
30483
30654
  [size]="11"
30484
30655
  aria-hidden="true"
30485
30656
  />
30657
+ <span class="strct-sr-only">{{ newTabLabel() }}</span>
30486
30658
  </a>
30487
30659
  }
30488
30660
  @case ('internal') {
@@ -30509,7 +30681,7 @@ class StrctMarkdown {
30509
30681
  }
30510
30682
  }
30511
30683
  </ng-template>
30512
- `, isInline: true, styles: [".strct-md{display:block;color:var(--t1);font-size:13px;line-height:1.55}.strct-md__p{margin:0 0 var(--space-2)}.strct-md__p:last-child{margin-bottom:0}.strct-md__h{margin:var(--space-3) 0 var(--space-2);font-size:14px;font-weight:600;color:var(--t1)}.strct-md__h:first-child{margin-top:0}.strct-md__list{margin:0 0 var(--space-2);padding-inline-start:20px}.strct-md__list li{margin-block:2px}.strct-md__quote{margin:0 0 var(--space-2);padding-inline-start:var(--space-3);border-inline-start:2px solid var(--b2);color:var(--t2)}.strct-md__rule{border:0;border-block-start:1px solid var(--b1);margin:var(--space-3) 0}.strct-md__codespan{font-family:var(--mono);font-size:.92em;background:var(--bg-2);border-radius:var(--radius-sm);padding:1px 4px}.strct-md__code{margin-block-end:var(--space-2)}.strct-md__link{color:var(--acc)}.strct-md__ext{margin-inline-start:2px;vertical-align:-1px}.strct-md__tablewrap{overflow-x:auto;margin-block-end:var(--space-2)}.strct-md__table{border-collapse:collapse;width:max-content;min-width:100%}.strct-md__table th,.strct-md__table td{border:1px solid var(--b1);padding:4px 8px;text-align:start}.strct-md__table th{background:var(--bg-2);font-weight:600}.strct-md__caret{display:inline-block;width:2px;height:1em;margin-inline-start:2px;vertical-align:-2px;background:var(--acc);animation:strct-md-caret 1s steps(2) infinite}@keyframes strct-md-caret{50%{opacity:0}}@media(prefers-reduced-motion:reduce){.strct-md__caret{animation:none}}\n"], dependencies: [{ kind: "component", type: StrctMarkdown, selector: "strct-markdown", inputs: ["source", "tree", "streaming", "headingOffset", "linkPolicy", "tokens"], outputs: ["navigate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StrctCode, selector: "strct-code", inputs: ["code", "title", "language", "copyable", "collapsible", "collapsed", "lineNumbers", "wrap", "maxHeight", "collapseLabel", "expandLabel", "regionLabel"], outputs: ["collapsedChange"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
30684
+ `, isInline: true, styles: [".strct-md{display:block;color:var(--t1);font-size:13px;line-height:1.55}.strct-md__p{margin:0 0 var(--space-2)}.strct-md__p:last-child{margin-bottom:0}.strct-md__h{margin:var(--space-3) 0 var(--space-2);font-size:14px;font-weight:600;color:var(--t1)}.strct-md__h:first-child{margin-top:0}.strct-md__list{margin:0 0 var(--space-2);padding-inline-start:20px}.strct-md__list li{margin-block:2px}.strct-md__quote{margin:0 0 var(--space-2);padding-inline-start:var(--space-3);border-inline-start:2px solid var(--b2);color:var(--t2)}.strct-md__rule{border:0;border-block-start:1px solid var(--b1);margin:var(--space-3) 0}.strct-md__codespan{font-family:var(--mono);font-size:.92em;background:var(--bg-2);border-radius:var(--radius-sm);padding:1px 4px}.strct-md__code{margin-block-end:var(--space-2)}.strct-md__link{color:var(--acc)}.strct-md__ext{margin-inline-start:2px;vertical-align:-1px}.strct-md__tablewrap{overflow-x:auto;margin-block-end:var(--space-2)}.strct-md__table{border-collapse:collapse;width:max-content;min-width:100%}.strct-md__table th,.strct-md__table td{border:1px solid var(--b1);padding:4px 8px;text-align:start}.strct-md__table th{background:var(--bg-2);font-weight:600}.strct-md__caret{display:inline-block;width:2px;height:1em;margin-inline-start:2px;vertical-align:-2px;background:var(--acc);animation:strct-md-caret 1s steps(2) infinite}@keyframes strct-md-caret{50%{opacity:0}}@media(prefers-reduced-motion:reduce){.strct-md__caret{animation:none}}\n"], dependencies: [{ kind: "component", type: StrctMarkdown, selector: "strct-markdown", inputs: ["source", "tree", "streaming", "headingOffset", "linkPolicy", "tokens", "breaks", "newTabLabel", "inheritedTokens"], outputs: ["navigate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StrctCode, selector: "strct-code", inputs: ["code", "title", "language", "copyable", "collapsible", "collapsed", "lineNumbers", "wrap", "maxHeight", "collapseLabel", "expandLabel", "regionLabel"], outputs: ["collapsedChange"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
30513
30685
  }
30514
30686
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctMarkdown, decorators: [{
30515
30687
  type: Component,
@@ -30658,10 +30830,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
30658
30830
  <!-- Blocks inside a list item or a quote. -->
30659
30831
  <ng-template #blockRun let-blocks>
30660
30832
  @for (b of blocks; track $index) {
30833
+ <!-- The nested view had no token templates of its own, so a claimed
30834
+ run inside a list item or a quote was drawn as plain text while
30835
+ the same run in a paragraph became a chip. -->
30661
30836
  <strct-markdown
30662
30837
  [tree]="[b]"
30663
30838
  [headingOffset]="headingOffset()"
30664
30839
  [linkPolicy]="linkPolicy()"
30840
+ [tokens]="tokens()"
30841
+ [breaks]="breaks()"
30842
+ [inheritedTokens]="allTokenDefs()"
30665
30843
  (navigate)="navigate.emit($event)"
30666
30844
  />
30667
30845
  }
@@ -30733,6 +30911,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
30733
30911
  [size]="11"
30734
30912
  aria-hidden="true"
30735
30913
  />
30914
+ <span class="strct-sr-only">{{ newTabLabel() }}</span>
30736
30915
  </a>
30737
30916
  }
30738
30917
  @case ('internal') {
@@ -30760,7 +30939,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
30760
30939
  }
30761
30940
  </ng-template>
30762
30941
  `, host: { class: 'strct-md' }, styles: [".strct-md{display:block;color:var(--t1);font-size:13px;line-height:1.55}.strct-md__p{margin:0 0 var(--space-2)}.strct-md__p:last-child{margin-bottom:0}.strct-md__h{margin:var(--space-3) 0 var(--space-2);font-size:14px;font-weight:600;color:var(--t1)}.strct-md__h:first-child{margin-top:0}.strct-md__list{margin:0 0 var(--space-2);padding-inline-start:20px}.strct-md__list li{margin-block:2px}.strct-md__quote{margin:0 0 var(--space-2);padding-inline-start:var(--space-3);border-inline-start:2px solid var(--b2);color:var(--t2)}.strct-md__rule{border:0;border-block-start:1px solid var(--b1);margin:var(--space-3) 0}.strct-md__codespan{font-family:var(--mono);font-size:.92em;background:var(--bg-2);border-radius:var(--radius-sm);padding:1px 4px}.strct-md__code{margin-block-end:var(--space-2)}.strct-md__link{color:var(--acc)}.strct-md__ext{margin-inline-start:2px;vertical-align:-1px}.strct-md__tablewrap{overflow-x:auto;margin-block-end:var(--space-2)}.strct-md__table{border-collapse:collapse;width:max-content;min-width:100%}.strct-md__table th,.strct-md__table td{border:1px solid var(--b1);padding:4px 8px;text-align:start}.strct-md__table th{background:var(--bg-2);font-weight:600}.strct-md__caret{display:inline-block;width:2px;height:1em;margin-inline-start:2px;vertical-align:-2px;background:var(--acc);animation:strct-md-caret 1s steps(2) infinite}@keyframes strct-md-caret{50%{opacity:0}}@media(prefers-reduced-motion:reduce){.strct-md__caret{animation:none}}\n"] }]
30763
- }], propDecorators: { source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], tree: [{ type: i0.Input, args: [{ isSignal: true, alias: "tree", required: false }] }], streaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "streaming", required: false }] }], headingOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingOffset", required: false }] }], linkPolicy: [{ type: i0.Input, args: [{ isSignal: true, alias: "linkPolicy", required: false }] }], tokens: [{ type: i0.Input, args: [{ isSignal: true, alias: "tokens", required: false }] }], navigate: [{ type: i0.Output, args: ["navigate"] }], tokenDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctMarkdownToken), { isSignal: true }] }] } });
30942
+ }], propDecorators: { source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], tree: [{ type: i0.Input, args: [{ isSignal: true, alias: "tree", required: false }] }], streaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "streaming", required: false }] }], headingOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingOffset", required: false }] }], linkPolicy: [{ type: i0.Input, args: [{ isSignal: true, alias: "linkPolicy", required: false }] }], tokens: [{ type: i0.Input, args: [{ isSignal: true, alias: "tokens", required: false }] }], breaks: [{ type: i0.Input, args: [{ isSignal: true, alias: "breaks", required: false }] }], newTabLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "newTabLabel", required: false }] }], inheritedTokens: [{ type: i0.Input, args: [{ isSignal: true, alias: "inheritedTokens", required: false }] }], navigate: [{ type: i0.Output, args: ["navigate"] }], ownTokenDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctMarkdownToken), { isSignal: true }] }] } });
30764
30943
 
30765
30944
  /**
30766
30945
  * The product switcher every multi-product console grows: a chip beside the
@@ -30863,22 +31042,6 @@ class StrctProductSwitcher {
30863
31042
  }
30864
31043
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctProductSwitcher, deps: [], target: i0.ɵɵFactoryTarget.Component });
30865
31044
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctProductSwitcher, isStandalone: true, selector: "strct-product-switcher", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, footerItems: { classPropertyName: "footerItems", publicName: "footerItems", isSignal: true, isRequired: false, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: false, transformFunction: null }, switchLabel: { classPropertyName: "switchLabel", publicName: "switchLabel", isSignal: true, isRequired: false, transformFunction: null }, shortLabelWidth: { classPropertyName: "shortLabelWidth", publicName: "shortLabelWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { current: "currentChange", opened: "opened", select: "select" }, host: { classAttribute: "strct-ps" }, viewQueries: [{ propertyName: "menu", first: true, predicate: ["menu"], descendants: true, isSignal: true }], ngImport: i0, template: `
30866
- <!-- What a row holds, whichever element carries it. -->
30867
- <ng-template #rowBody let-item>
30868
- @if (item.icon) {
30869
- <strct-icon strctDropdownItemIcon [tone]="item.tone ?? ''" [name]="item.icon" [size]="16" />
30870
- }
30871
- <span strctDropdownItemLabel>{{ item.name }}</span>
30872
- @if (item.description) {
30873
- <span strctDropdownItemDescription>
30874
- @if (item.status) {
30875
- <strct-status-dot [status]="item.status" />
30876
- }
30877
- {{ item.description }}
30878
- </span>
30879
- }
30880
- </ng-template>
30881
-
30882
31045
  <!-- A row is a link where the product has an address, so it can be opened
30883
31046
  in a new tab — and a menuitemradio either way, checked on the one you
30884
31047
  are in. -->
@@ -30890,7 +31053,23 @@ class StrctProductSwitcher {
30890
31053
  [selected]="item.id === current()"
30891
31054
  (click)="pick(item, $event)"
30892
31055
  >
30893
- <ng-container *ngTemplateOutlet="rowBody; context: { $implicit: item }" />
31056
+ @if (item.icon) {
31057
+ <strct-icon
31058
+ strctDropdownItemIcon
31059
+ [tone]="item.tone ?? ''"
31060
+ [name]="item.icon"
31061
+ [size]="16"
31062
+ />
31063
+ }
31064
+ <span strctDropdownItemLabel>{{ item.name }}</span>
31065
+ @if (item.description) {
31066
+ <span strctDropdownItemDescription>
31067
+ @if (item.status) {
31068
+ <strct-status-dot [status]="item.status" />
31069
+ }
31070
+ {{ item.description }}
31071
+ </span>
31072
+ }
30894
31073
  </a>
30895
31074
  } @else if (item.href && !item.disabled) {
30896
31075
  <a
@@ -30899,7 +31078,23 @@ class StrctProductSwitcher {
30899
31078
  [selected]="item.id === current()"
30900
31079
  (click)="pick(item, $event)"
30901
31080
  >
30902
- <ng-container *ngTemplateOutlet="rowBody; context: { $implicit: item }" />
31081
+ @if (item.icon) {
31082
+ <strct-icon
31083
+ strctDropdownItemIcon
31084
+ [tone]="item.tone ?? ''"
31085
+ [name]="item.icon"
31086
+ [size]="16"
31087
+ />
31088
+ }
31089
+ <span strctDropdownItemLabel>{{ item.name }}</span>
31090
+ @if (item.description) {
31091
+ <span strctDropdownItemDescription>
31092
+ @if (item.status) {
31093
+ <strct-status-dot [status]="item.status" />
31094
+ }
31095
+ {{ item.description }}
31096
+ </span>
31097
+ }
30903
31098
  </a>
30904
31099
  } @else {
30905
31100
  <strct-dropdown-item
@@ -30907,7 +31102,23 @@ class StrctProductSwitcher {
30907
31102
  [disabled]="!!item.disabled"
30908
31103
  (click)="pick(item)"
30909
31104
  >
30910
- <ng-container *ngTemplateOutlet="rowBody; context: { $implicit: item }" />
31105
+ @if (item.icon) {
31106
+ <strct-icon
31107
+ strctDropdownItemIcon
31108
+ [tone]="item.tone ?? ''"
31109
+ [name]="item.icon"
31110
+ [size]="16"
31111
+ />
31112
+ }
31113
+ <span strctDropdownItemLabel>{{ item.name }}</span>
31114
+ @if (item.description) {
31115
+ <span strctDropdownItemDescription>
31116
+ @if (item.status) {
31117
+ <strct-status-dot [status]="item.status" />
31118
+ }
31119
+ {{ item.description }}
31120
+ </span>
31121
+ }
30911
31122
  </strct-dropdown-item>
30912
31123
  }
30913
31124
  </ng-template>
@@ -30947,7 +31158,7 @@ class StrctProductSwitcher {
30947
31158
  class="strct-ps__icon"
30948
31159
  [name]="item.icon"
30949
31160
  [size]="16"
30950
- [style.color]="item.tone || null"
31161
+ [style.color]="item.headerTone || item.tone || null"
30951
31162
  />
30952
31163
  }
30953
31164
  <span class="strct-ps__label">{{ chipText() }}</span>
@@ -30970,22 +31181,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
30970
31181
  StrctDropdownItemDescription,
30971
31182
  StrctDropdownDivider,
30972
31183
  ], template: `
30973
- <!-- What a row holds, whichever element carries it. -->
30974
- <ng-template #rowBody let-item>
30975
- @if (item.icon) {
30976
- <strct-icon strctDropdownItemIcon [tone]="item.tone ?? ''" [name]="item.icon" [size]="16" />
30977
- }
30978
- <span strctDropdownItemLabel>{{ item.name }}</span>
30979
- @if (item.description) {
30980
- <span strctDropdownItemDescription>
30981
- @if (item.status) {
30982
- <strct-status-dot [status]="item.status" />
30983
- }
30984
- {{ item.description }}
30985
- </span>
30986
- }
30987
- </ng-template>
30988
-
30989
31184
  <!-- A row is a link where the product has an address, so it can be opened
30990
31185
  in a new tab — and a menuitemradio either way, checked on the one you
30991
31186
  are in. -->
@@ -30997,7 +31192,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
30997
31192
  [selected]="item.id === current()"
30998
31193
  (click)="pick(item, $event)"
30999
31194
  >
31000
- <ng-container *ngTemplateOutlet="rowBody; context: { $implicit: item }" />
31195
+ @if (item.icon) {
31196
+ <strct-icon
31197
+ strctDropdownItemIcon
31198
+ [tone]="item.tone ?? ''"
31199
+ [name]="item.icon"
31200
+ [size]="16"
31201
+ />
31202
+ }
31203
+ <span strctDropdownItemLabel>{{ item.name }}</span>
31204
+ @if (item.description) {
31205
+ <span strctDropdownItemDescription>
31206
+ @if (item.status) {
31207
+ <strct-status-dot [status]="item.status" />
31208
+ }
31209
+ {{ item.description }}
31210
+ </span>
31211
+ }
31001
31212
  </a>
31002
31213
  } @else if (item.href && !item.disabled) {
31003
31214
  <a
@@ -31006,7 +31217,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
31006
31217
  [selected]="item.id === current()"
31007
31218
  (click)="pick(item, $event)"
31008
31219
  >
31009
- <ng-container *ngTemplateOutlet="rowBody; context: { $implicit: item }" />
31220
+ @if (item.icon) {
31221
+ <strct-icon
31222
+ strctDropdownItemIcon
31223
+ [tone]="item.tone ?? ''"
31224
+ [name]="item.icon"
31225
+ [size]="16"
31226
+ />
31227
+ }
31228
+ <span strctDropdownItemLabel>{{ item.name }}</span>
31229
+ @if (item.description) {
31230
+ <span strctDropdownItemDescription>
31231
+ @if (item.status) {
31232
+ <strct-status-dot [status]="item.status" />
31233
+ }
31234
+ {{ item.description }}
31235
+ </span>
31236
+ }
31010
31237
  </a>
31011
31238
  } @else {
31012
31239
  <strct-dropdown-item
@@ -31014,7 +31241,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
31014
31241
  [disabled]="!!item.disabled"
31015
31242
  (click)="pick(item)"
31016
31243
  >
31017
- <ng-container *ngTemplateOutlet="rowBody; context: { $implicit: item }" />
31244
+ @if (item.icon) {
31245
+ <strct-icon
31246
+ strctDropdownItemIcon
31247
+ [tone]="item.tone ?? ''"
31248
+ [name]="item.icon"
31249
+ [size]="16"
31250
+ />
31251
+ }
31252
+ <span strctDropdownItemLabel>{{ item.name }}</span>
31253
+ @if (item.description) {
31254
+ <span strctDropdownItemDescription>
31255
+ @if (item.status) {
31256
+ <strct-status-dot [status]="item.status" />
31257
+ }
31258
+ {{ item.description }}
31259
+ </span>
31260
+ }
31018
31261
  </strct-dropdown-item>
31019
31262
  }
31020
31263
  </ng-template>
@@ -31054,7 +31297,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
31054
31297
  class="strct-ps__icon"
31055
31298
  [name]="item.icon"
31056
31299
  [size]="16"
31057
- [style.color]="item.tone || null"
31300
+ [style.color]="item.headerTone || item.tone || null"
31058
31301
  />
31059
31302
  }
31060
31303
  <span class="strct-ps__label">{{ chipText() }}</span>