@akcelik/strct 4.12.0 → 4.13.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.
@@ -2998,6 +2998,15 @@ class StrctMenuPanel {
2998
2998
  ...(ngDevMode ? [{ debugName: "y" }] : /* istanbul ignore next */ []));
2999
2999
  /** Render as a nested submenu panel. */
3000
3000
  submenu = input(false, { ...(ngDevMode ? { debugName: "submenu" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
3001
+ /** The anchor's viewport rect, when the menu is placed against a control. */
3002
+ anchorRect = input(null, /* @ts-ignore */
3003
+ ...(ngDevMode ? [{ debugName: "anchorRect" }] : /* istanbul ignore next */ []));
3004
+ /** Preferred side and alignment against `anchorRect`. */
3005
+ placement = input('bottom-start', /* @ts-ignore */
3006
+ ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
3007
+ /** Gap between the anchor and the menu. */
3008
+ offset = input(4, /* @ts-ignore */
3009
+ ...(ngDevMode ? [{ debugName: "offset" }] : /* istanbul ignore next */ []));
3001
3010
  /** Emitted when an item is selected. */
3002
3011
  select = output();
3003
3012
  /** Emitted when the menu requests closing. */
@@ -3008,6 +3017,13 @@ class StrctMenuPanel {
3008
3017
  ...(ngDevMode ? [{ debugName: "posX" }] : /* istanbul ignore next */ []));
3009
3018
  posY = signal(0, /* @ts-ignore */
3010
3019
  ...(ngDevMode ? [{ debugName: "posY" }] : /* istanbul ignore next */ []));
3020
+ /**
3021
+ * An anchored menu is placed from its real size, which is known only after it
3022
+ * renders — so it stays hidden for that one frame rather than appearing in
3023
+ * the wrong place first.
3024
+ */
3025
+ placed = signal(true, /* @ts-ignore */
3026
+ ...(ngDevMode ? [{ debugName: "placed" }] : /* istanbul ignore next */ []));
3011
3027
  /** Vertical offset of a submenu fly-out (matches the CSS `top: -5px` default). */
3012
3028
  subTop = signal(-5, /* @ts-ignore */
3013
3029
  ...(ngDevMode ? [{ debugName: "subTop" }] : /* istanbul ignore next */ []));
@@ -3032,15 +3048,60 @@ class StrctMenuPanel {
3032
3048
  constructor() {
3033
3049
  this.posX.set(this.x());
3034
3050
  this.posY.set(this.y());
3051
+ if (this.anchorRect())
3052
+ this.placed.set(false);
3035
3053
  afterNextRender(() => {
3036
3054
  // Open on the first entry that can act; a disabled-but-hinted one is
3037
3055
  // reachable by arrow keys, not the landing spot.
3038
3056
  const nav = this.navIndices();
3039
3057
  this.activeIndex.set(nav.find((i) => !this.items()[i].disabled) ?? nav[0] ?? 0);
3040
- this.clampToViewport();
3058
+ if (this.anchorRect())
3059
+ this.placeAgainstAnchor();
3060
+ else
3061
+ this.clampToViewport();
3062
+ this.placed.set(true);
3041
3063
  this.focusItem(this.activeIndex());
3042
3064
  });
3043
3065
  }
3066
+ /**
3067
+ * Place the panel against its anchor from the panel's measured size: the
3068
+ * preferred side when it fits, the opposite side when it does not and the
3069
+ * opposite side does, and clamped on the cross axis either way.
3070
+ */
3071
+ placeAgainstAnchor() {
3072
+ const host = this.host.nativeElement;
3073
+ const r = this.anchorRect();
3074
+ const w = host.offsetWidth;
3075
+ const h = host.offsetHeight;
3076
+ const vw = window.innerWidth;
3077
+ const vh = window.innerHeight;
3078
+ const gap = this.offset();
3079
+ const m = 6;
3080
+ const [preferred, align] = this.placement().split('-');
3081
+ let side = preferred;
3082
+ if (side === 'bottom' && r.bottom + gap + h > vh - m && r.top - gap - h >= m)
3083
+ side = 'top';
3084
+ else if (side === 'top' && r.top - gap - h < m && r.bottom + gap + h <= vh - m)
3085
+ side = 'bottom';
3086
+ else if (side === 'right' && r.right + gap + w > vw - m && r.left - gap - w >= m)
3087
+ side = 'left';
3088
+ else if (side === 'left' && r.left - gap - w < m && r.right + gap + w <= vw - m)
3089
+ side = 'right';
3090
+ let x;
3091
+ let y;
3092
+ if (side === 'bottom' || side === 'top') {
3093
+ x = align === 'end' ? r.right - w : r.left;
3094
+ y = side === 'bottom' ? r.bottom + gap : r.top - gap - h;
3095
+ }
3096
+ else {
3097
+ x = side === 'right' ? r.right + gap : r.left - gap - w;
3098
+ y = align === 'end' ? r.bottom - h : r.top;
3099
+ }
3100
+ this.posX.set(Math.max(m, Math.min(x, vw - w - m)));
3101
+ this.posY.set(Math.max(m, Math.min(y, vh - h - m)));
3102
+ const rtl = getComputedStyle(host).direction === 'rtl';
3103
+ this.flipLeft.set(rtl ? this.posX() < 220 : this.posX() + w > vw - 220);
3104
+ }
3044
3105
  clampToViewport() {
3045
3106
  const host = this.host.nativeElement;
3046
3107
  const vh = window.innerHeight;
@@ -3172,7 +3233,7 @@ class StrctMenuPanel {
3172
3233
  }
3173
3234
  }
3174
3235
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctMenuPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
3175
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctMenuPanel, isStandalone: true, selector: "strct-menu-panel", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, x: { classPropertyName: "x", publicName: "x", isSignal: true, isRequired: false, transformFunction: null }, y: { classPropertyName: "y", publicName: "y", isSignal: true, isRequired: false, transformFunction: null }, submenu: { classPropertyName: "submenu", publicName: "submenu", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { select: "select", close: "close", back: "back" }, host: { properties: { "style.position": "submenu() ? null : 'fixed'", "style.left.px": "submenu() ? null : posX()", "style.top.px": "submenu() ? subTop() : posY()", "style.zIndex": "submenu() ? null : 1100" }, classAttribute: "strct-menu-host" }, ngImport: i0, template: `
3236
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctMenuPanel, isStandalone: true, selector: "strct-menu-panel", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, x: { classPropertyName: "x", publicName: "x", isSignal: true, isRequired: false, transformFunction: null }, y: { classPropertyName: "y", publicName: "y", isSignal: true, isRequired: false, transformFunction: null }, submenu: { classPropertyName: "submenu", publicName: "submenu", isSignal: true, isRequired: false, transformFunction: null }, anchorRect: { classPropertyName: "anchorRect", publicName: "anchorRect", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { select: "select", close: "close", back: "back" }, host: { properties: { "style.position": "submenu() ? null : 'fixed'", "style.visibility": "placed() ? null : 'hidden'", "style.left.px": "submenu() ? null : posX()", "style.top.px": "submenu() ? subTop() : posY()", "style.zIndex": "submenu() ? null : 1100" }, classAttribute: "strct-menu-host" }, ngImport: i0, template: `
3176
3237
  <div class="strct-menu" role="menu" tabindex="-1" (keydown)="onKeydown($event)">
3177
3238
  @for (item of items(); track $index; let i = $index) {
3178
3239
  @if (item.divider) {
@@ -3241,7 +3302,7 @@ class StrctMenuPanel {
3241
3302
  }
3242
3303
  }
3243
3304
  </div>
3244
- `, isInline: true, styles: [".strct-menu-host{display:block}.strct-menu{min-width:180px;padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-md);box-shadow:var(--shh);animation:strct-menu-in .1s ease}.strct-menu:focus{outline:none}.strct-menu__wrap{position:relative}.strct-menu__item{display:flex;align-items:center;gap:8px;width:100%;padding:7px 8px 7px 10px;border:0;border-radius:5px;cursor:pointer;background:transparent;color:var(--t1);font-size:13px;font-family:var(--font);text-align:start}.strct-menu__item:hover:not([aria-disabled=true]),.strct-menu__item--active:not([aria-disabled=true]){background:var(--bg-3)}.strct-menu__item:focus-visible{outline:none;background:var(--bg-3)}.strct-menu__item--critical{color:var(--critical)}.strct-menu__item--critical:hover:not([aria-disabled=true]),.strct-menu__item--critical.strct-menu__item--active:not([aria-disabled=true]){background:var(--critical-bg)}.strct-menu__item[aria-disabled=true]{opacity:.45;cursor:not-allowed}.strct-menu__icon{color:var(--t2);flex-shrink:0}.strct-menu__item--critical .strct-menu__icon{color:var(--critical)}.strct-menu__icon-spacer{width:14px;flex-shrink:0}.strct-menu__label{flex:1;white-space:nowrap}.strct-menu__arrow{color:var(--t3);flex-shrink:0}.strct-menu__sep{height:1px;margin:4px 6px;background:var(--b1)}.strct-menu__subpanel{position:absolute;top:-5px;inset-inline-start:100%;margin-inline-start:2px;z-index:var(--z-base)}.strct-menu__subpanel--flip{inset-inline-start:auto;inset-inline-end:100%;margin-inline-start:0;margin-inline-end:2px}[dir=rtl] .strct-menu__arrow{transform:rotate(180deg)}@keyframes strct-menu-in{0%{opacity:0;transform:scale(.97)}}\n"], dependencies: [{ kind: "component", type: StrctMenuPanel, selector: "strct-menu-panel", inputs: ["items", "data", "x", "y", "submenu"], outputs: ["select", "close", "back"] }, { 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 });
3305
+ `, isInline: true, styles: [".strct-menu-host{display:block}.strct-menu{min-width:180px;padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-md);box-shadow:var(--shh);animation:strct-menu-in .1s ease}.strct-menu:focus{outline:none}.strct-menu__wrap{position:relative}.strct-menu__item{display:flex;align-items:center;gap:8px;width:100%;padding:7px 8px 7px 10px;border:0;border-radius:5px;cursor:pointer;background:transparent;color:var(--t1);font-size:13px;font-family:var(--font);text-align:start}.strct-menu__item:hover:not([aria-disabled=true]),.strct-menu__item--active:not([aria-disabled=true]){background:var(--bg-3)}.strct-menu__item:focus-visible{outline:none;background:var(--bg-3)}.strct-menu__item--critical{color:var(--critical)}.strct-menu__item--critical:hover:not([aria-disabled=true]),.strct-menu__item--critical.strct-menu__item--active:not([aria-disabled=true]){background:var(--critical-bg)}.strct-menu__item[aria-disabled=true]{opacity:.45;cursor:not-allowed}.strct-menu__icon{color:var(--t2);flex-shrink:0}.strct-menu__item--critical .strct-menu__icon{color:var(--critical)}.strct-menu__icon-spacer{width:14px;flex-shrink:0}.strct-menu__label{flex:1;white-space:nowrap}.strct-menu__arrow{color:var(--t3);flex-shrink:0}.strct-menu__sep{height:1px;margin:4px 6px;background:var(--b1)}.strct-menu__subpanel{position:absolute;top:-5px;inset-inline-start:100%;margin-inline-start:2px;z-index:var(--z-base)}.strct-menu__subpanel--flip{inset-inline-start:auto;inset-inline-end:100%;margin-inline-start:0;margin-inline-end:2px}[dir=rtl] .strct-menu__arrow{transform:rotate(180deg)}@keyframes strct-menu-in{0%{opacity:0;transform:scale(.97)}}\n"], dependencies: [{ kind: "component", type: StrctMenuPanel, selector: "strct-menu-panel", inputs: ["items", "data", "x", "y", "submenu", "anchorRect", "placement", "offset"], outputs: ["select", "close", "back"] }, { 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 });
3245
3306
  }
3246
3307
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctMenuPanel, decorators: [{
3247
3308
  type: Component,
@@ -3317,11 +3378,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
3317
3378
  `, host: {
3318
3379
  class: 'strct-menu-host',
3319
3380
  '[style.position]': "submenu() ? null : 'fixed'",
3381
+ '[style.visibility]': "placed() ? null : 'hidden'",
3320
3382
  '[style.left.px]': 'submenu() ? null : posX()',
3321
3383
  '[style.top.px]': 'submenu() ? subTop() : posY()',
3322
3384
  '[style.zIndex]': 'submenu() ? null : 1100',
3323
3385
  }, styles: [".strct-menu-host{display:block}.strct-menu{min-width:180px;padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-md);box-shadow:var(--shh);animation:strct-menu-in .1s ease}.strct-menu:focus{outline:none}.strct-menu__wrap{position:relative}.strct-menu__item{display:flex;align-items:center;gap:8px;width:100%;padding:7px 8px 7px 10px;border:0;border-radius:5px;cursor:pointer;background:transparent;color:var(--t1);font-size:13px;font-family:var(--font);text-align:start}.strct-menu__item:hover:not([aria-disabled=true]),.strct-menu__item--active:not([aria-disabled=true]){background:var(--bg-3)}.strct-menu__item:focus-visible{outline:none;background:var(--bg-3)}.strct-menu__item--critical{color:var(--critical)}.strct-menu__item--critical:hover:not([aria-disabled=true]),.strct-menu__item--critical.strct-menu__item--active:not([aria-disabled=true]){background:var(--critical-bg)}.strct-menu__item[aria-disabled=true]{opacity:.45;cursor:not-allowed}.strct-menu__icon{color:var(--t2);flex-shrink:0}.strct-menu__item--critical .strct-menu__icon{color:var(--critical)}.strct-menu__icon-spacer{width:14px;flex-shrink:0}.strct-menu__label{flex:1;white-space:nowrap}.strct-menu__arrow{color:var(--t3);flex-shrink:0}.strct-menu__sep{height:1px;margin:4px 6px;background:var(--b1)}.strct-menu__subpanel{position:absolute;top:-5px;inset-inline-start:100%;margin-inline-start:2px;z-index:var(--z-base)}.strct-menu__subpanel--flip{inset-inline-start:auto;inset-inline-end:100%;margin-inline-start:0;margin-inline-end:2px}[dir=rtl] .strct-menu__arrow{transform:rotate(180deg)}@keyframes strct-menu-in{0%{opacity:0;transform:scale(.97)}}\n"] }]
3324
- }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], x: [{ type: i0.Input, args: [{ isSignal: true, alias: "x", required: false }] }], y: [{ type: i0.Input, args: [{ isSignal: true, alias: "y", required: false }] }], submenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "submenu", required: false }] }], select: [{ type: i0.Output, args: ["select"] }], close: [{ type: i0.Output, args: ["close"] }], back: [{ type: i0.Output, args: ["back"] }] } });
3386
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], x: [{ type: i0.Input, args: [{ isSignal: true, alias: "x", required: false }] }], y: [{ type: i0.Input, args: [{ isSignal: true, alias: "y", required: false }] }], submenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "submenu", required: false }] }], anchorRect: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchorRect", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], select: [{ type: i0.Output, args: ["select"] }], close: [{ type: i0.Output, args: ["close"] }], back: [{ type: i0.Output, args: ["back"] }] } });
3325
3387
  /**
3326
3388
  * Imperatively opens the data-driven menu panel, portaled into `<body>`. Shared
3327
3389
  * by the `[strctContextMenu]` directive (right-click) and any click trigger such
@@ -3343,8 +3405,20 @@ class StrctMenuService {
3343
3405
  const ref = createComponent(StrctMenuPanel, { environmentInjector: this.envInjector });
3344
3406
  ref.setInput('items', opts.items);
3345
3407
  ref.setInput('data', opts.data);
3346
- ref.setInput('x', opts.x);
3347
- ref.setInput('y', opts.y);
3408
+ ref.setInput('x', opts.x ?? 0);
3409
+ ref.setInput('y', opts.y ?? 0);
3410
+ if (opts.anchor) {
3411
+ const rect = opts.anchor instanceof Element ? opts.anchor.getBoundingClientRect() : opts.anchor;
3412
+ ref.setInput('anchorRect', rect);
3413
+ ref.setInput('placement', opts.placement ?? 'bottom-start');
3414
+ ref.setInput('offset', opts.offset ?? 4);
3415
+ // Focus goes back to the control the menu belongs to, when that control
3416
+ // can take it — otherwise to whatever had focus before.
3417
+ if (opts.anchor instanceof HTMLElement &&
3418
+ opts.anchor.matches('button, a[href], input, select, textarea, [tabindex]')) {
3419
+ this.restoreTo = opts.anchor;
3420
+ }
3421
+ }
3348
3422
  ref.instance.select.subscribe((item) => {
3349
3423
  item.action?.(opts.data);
3350
3424
  opts.onSelect?.(item);
@@ -5003,7 +5077,10 @@ class StrctDropdown {
5003
5077
  onInnerActivate(event) {
5004
5078
  if (this.popover())
5005
5079
  return;
5006
- const item = event.target?.closest('strct-dropdown-item');
5080
+ const target = event.target;
5081
+ if (target?.closest('.strct-dd__itemaction'))
5082
+ return; // the second action is not the item
5083
+ const item = target?.closest('strct-dropdown-item');
5007
5084
  if (item && item.getAttribute('aria-disabled') !== 'true')
5008
5085
  this.close(true);
5009
5086
  }
@@ -5035,10 +5112,39 @@ class StrctDropdown {
5035
5112
  if (target.getAttribute('aria-disabled') !== 'true')
5036
5113
  target.click();
5037
5114
  }
5115
+ else if (key === 'ArrowRight' || key === 'ArrowLeft' || key === 'Delete') {
5116
+ this.onItemActionKey(event, key);
5117
+ }
5038
5118
  else if (key === 'Tab') {
5039
5119
  this.close();
5040
5120
  }
5041
5121
  }
5122
+ /**
5123
+ * An item with a trailing action has two targets: the right arrow reaches the
5124
+ * action from its item, the left arrow returns, and Delete on the item
5125
+ * triggers it (the WAI-ARIA pattern for a secondary action). Keys that do not
5126
+ * apply are left alone, so submenus keep their own arrow behaviour.
5127
+ */
5128
+ onItemActionKey(event, key) {
5129
+ const target = event.target;
5130
+ if (key === 'ArrowLeft') {
5131
+ const item = target.closest('strct-dropdown-item');
5132
+ if (!target.classList.contains('strct-dd__itemaction') || !item)
5133
+ return;
5134
+ event.preventDefault();
5135
+ item.focus();
5136
+ return;
5137
+ }
5138
+ const item = target.closest('strct-dropdown-item');
5139
+ const action = item?.querySelector('.strct-dd__itemaction');
5140
+ if (!item || item !== target || !action)
5141
+ return;
5142
+ event.preventDefault();
5143
+ if (key === 'ArrowRight')
5144
+ action.focus();
5145
+ else
5146
+ action.click();
5147
+ }
5042
5148
  enabledItems() {
5043
5149
  return [
5044
5150
  ...this.host.nativeElement.querySelectorAll('strct-dropdown-item:not([aria-disabled="true"]), strct-submenu .strct-submenu__trigger'),
@@ -5174,6 +5280,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
5174
5280
  }] });
5175
5281
  let dropdownItemCounter = 0;
5176
5282
  /** A selectable row inside a `<strct-dropdown>`. */
5283
+ /**
5284
+ * A second action at the end of a menu item — "delete this saved view" beside
5285
+ * "open it". It stops its own click from reaching the item, so the item is not
5286
+ * activated and the menu stays open, and it stays out of the Tab order: the
5287
+ * right arrow reaches it from its item, the left arrow returns, and Delete on
5288
+ * the item triggers it.
5289
+ */
5290
+ class StrctDropdownItemAction {
5291
+ onClick(event) {
5292
+ event.stopPropagation();
5293
+ }
5294
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDropdownItemAction, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5295
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctDropdownItemAction, isStandalone: true, selector: "[strctDropdownItemAction]", host: { attributes: { "tabindex": "-1" }, listeners: { "click": "onClick($event)" }, classAttribute: "strct-dd__itemaction" }, ngImport: i0 });
5296
+ }
5297
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDropdownItemAction, decorators: [{
5298
+ type: Directive,
5299
+ args: [{
5300
+ selector: '[strctDropdownItemAction]',
5301
+ host: {
5302
+ class: 'strct-dd__itemaction',
5303
+ tabindex: '-1',
5304
+ '(click)': 'onClick($event)',
5305
+ },
5306
+ }]
5307
+ }] });
5177
5308
  class StrctDropdownItem {
5178
5309
  /**
5179
5310
  * Select-like usage: bind `selected` and the item becomes a
@@ -5217,12 +5348,15 @@ class StrctDropdownItem {
5217
5348
  }
5218
5349
  </span>
5219
5350
  }
5351
+ <!-- Declared before the catch-all so its selector wins; CSS order and an
5352
+ auto margin put it at the item's end. -->
5353
+ <ng-content select="[strctDropdownItemAction]" />
5220
5354
  <ng-content />
5221
5355
  @if (hint()) {
5222
5356
  <!-- hidden: kept out of the item's accessible NAME, still read as its
5223
5357
  description through aria-describedby. -->
5224
5358
  <span [id]="hintId" hidden>{{ hint() }}</span>
5225
- }`, isInline: true, styles: [".strct-dd__item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:5px;cursor:pointer;font-size:13px;color:var(--t1)}.strct-dd__item:hover,.strct-dd__item:focus-visible{background:var(--bg-3);outline:none}.strct-dd__check{display:inline-flex;width:14px;flex:none;color:var(--acc)}.strct-dd__item--selected{color:var(--t1);font-weight:600;background:var(--acc-s)}.strct-dd__item--critical{color:var(--critical)}.strct-dd__item--critical:hover{background:var(--critical-bg)}.strct-dd__item[aria-disabled=true]{color:var(--t4);pointer-events:none}.strct-dd__item--hinted[aria-disabled=true]{pointer-events:auto;cursor:not-allowed}.strct-dd__item--hinted[aria-disabled=true]:hover{background:transparent}\n"], dependencies: [{ 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 });
5359
+ }`, isInline: true, styles: [".strct-dd__item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:5px;cursor:pointer;font-size:13px;color:var(--t1)}.strct-dd__item:hover,.strct-dd__item:focus-visible{background:var(--bg-3);outline:none}.strct-dd__itemaction{order:1;margin-inline-start:auto;flex:none}.strct-dd__check{display:inline-flex;width:14px;flex:none;color:var(--acc)}.strct-dd__item--selected{color:var(--t1);font-weight:600;background:var(--acc-s)}.strct-dd__item--critical{color:var(--critical)}.strct-dd__item--critical:hover{background:var(--critical-bg)}.strct-dd__item[aria-disabled=true]{color:var(--t4);pointer-events:none}.strct-dd__item--hinted[aria-disabled=true]{pointer-events:auto;cursor:not-allowed}.strct-dd__item--hinted[aria-disabled=true]:hover{background:transparent}\n"], dependencies: [{ 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 });
5226
5360
  }
5227
5361
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDropdownItem, decorators: [{
5228
5362
  type: Component,
@@ -5233,6 +5367,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
5233
5367
  }
5234
5368
  </span>
5235
5369
  }
5370
+ <!-- Declared before the catch-all so its selector wins; CSS order and an
5371
+ auto margin put it at the item's end. -->
5372
+ <ng-content select="[strctDropdownItemAction]" />
5236
5373
  <ng-content />
5237
5374
  @if (hint()) {
5238
5375
  <!-- hidden: kept out of the item's accessible NAME, still read as its
@@ -5250,7 +5387,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
5250
5387
  '[class.strct-dd__item--critical]': 'critical()',
5251
5388
  '[class.strct-dd__item--selected]': 'selected() === true',
5252
5389
  '[attr.aria-disabled]': 'disabled() || null',
5253
- }, styles: [".strct-dd__item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:5px;cursor:pointer;font-size:13px;color:var(--t1)}.strct-dd__item:hover,.strct-dd__item:focus-visible{background:var(--bg-3);outline:none}.strct-dd__check{display:inline-flex;width:14px;flex:none;color:var(--acc)}.strct-dd__item--selected{color:var(--t1);font-weight:600;background:var(--acc-s)}.strct-dd__item--critical{color:var(--critical)}.strct-dd__item--critical:hover{background:var(--critical-bg)}.strct-dd__item[aria-disabled=true]{color:var(--t4);pointer-events:none}.strct-dd__item--hinted[aria-disabled=true]{pointer-events:auto;cursor:not-allowed}.strct-dd__item--hinted[aria-disabled=true]:hover{background:transparent}\n"] }]
5390
+ }, styles: [".strct-dd__item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:5px;cursor:pointer;font-size:13px;color:var(--t1)}.strct-dd__item:hover,.strct-dd__item:focus-visible{background:var(--bg-3);outline:none}.strct-dd__itemaction{order:1;margin-inline-start:auto;flex:none}.strct-dd__check{display:inline-flex;width:14px;flex:none;color:var(--acc)}.strct-dd__item--selected{color:var(--t1);font-weight:600;background:var(--acc-s)}.strct-dd__item--critical{color:var(--critical)}.strct-dd__item--critical:hover{background:var(--critical-bg)}.strct-dd__item[aria-disabled=true]{color:var(--t4);pointer-events:none}.strct-dd__item--hinted[aria-disabled=true]{pointer-events:auto;cursor:not-allowed}.strct-dd__item--hinted[aria-disabled=true]:hover{background:transparent}\n"] }]
5254
5391
  }], ctorParameters: () => [], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], critical: [{ type: i0.Input, args: [{ isSignal: true, alias: "critical", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }] } });
5255
5392
  /** Thin separator between groups of menu items. */
5256
5393
  class StrctDropdownDivider {
@@ -23610,5 +23747,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
23610
23747
  * Generated bundle index. Do not edit.
23611
23748
  */
23612
23749
 
23613
- export { FOCUSABLE_SELECTOR, STRCT_DP_DOW, STRCT_DP_DOW_FULL, STRCT_DP_MONTHS, STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_NOTIFICATION_HISTORY_LIMIT, STRCT_PALETTES, STRCT_RAW_ICONS, STRCT_TIME_RANGE_PRESETS, STRCT_WIZARD_DEFAULTS, StrctAccordion, StrctAccordionPanel, StrctAlert, StrctAnnouncer, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctBytesPipe, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCardHeaderActions, StrctCardHeaderMeta, StrctCardHeaderNote, StrctCascadeColumn, StrctCascadeHost, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChart, StrctCheckbox, StrctChips, StrctCode, StrctCodeInline, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctConfirmOutlet, StrctConfirmService, StrctContextMenu, StrctContextMenuTrigger, StrctControlDescription, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatagridActionBarCaption, StrctDatepicker, StrctDatetimePicker, StrctDesc, StrctDescriptionList, StrctDiff, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctDropdownTrigger, StrctDurationPipe, StrctEmptyState, StrctField, StrctFieldGroup, StrctFieldHint, StrctFieldPrefix, StrctFieldSuffix, StrctFile, StrctFilterBar, StrctFlow, StrctFooter, StrctGauge, StrctHeader, StrctHeatmap, StrctHero, StrctHotkeysHelp, StrctHotkeysService, StrctIcon, StrctInlineEdit, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctList, StrctListItem, StrctListItemDescription, StrctListItemLeading, StrctListItemMeta, StrctListItemTrailing, StrctLogViewer, StrctLogin, StrctMenuPanel, StrctMenuService, StrctMenubar, StrctMetricTile, StrctModal, StrctModalContent, StrctNav, StrctNavItem, StrctNotificationCenter, StrctNumber, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPageHeaderTitleMeta, StrctPagination, StrctPassword, StrctPopover, StrctPopoverTrigger, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRatePipe, StrctRating, StrctReorder, StrctReorderItem, StrctRowDetailDef, StrctSearchbox, StrctSectionHeader, StrctSectionHeaderActions, StrctSectionHeaderMeta, StrctSectionMenu, StrctSegmented, StrctSelect, StrctShell, StrctShellService, StrctSiPipe, StrctSignpost, StrctSignpostTrigger, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctSplitButton, StrctSplitter, StrctStack, StrctStackItem, StrctStatusDot, StrctStep, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctTagLeading, StrctThemeService, StrctThemeSwitcher, StrctTimeRangePicker, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctToolbar, StrctToolbarCaption, StrctToolbarSpacer, StrctTooltip, StrctTour, StrctTransfer, StrctTree, StrctTreeNode, StrctTreeSelect, StrctVerticalNav, StrctWatermark, StrctWizard, StrctWizardAside, focusFirstIn, keepTabInside, lockBodyScroll, parseAnsi, provideStrctWizardDefaults, registerStrctIcon, restoreFocus, saveFocusedElement, strctComputeDiff, strctDpPad, strctFormatBytes, strctFormatDuration, strctFormatRate, strctFormatSi, strctValidationIcon, strctValidationTone, unlockBodyScroll };
23750
+ export { FOCUSABLE_SELECTOR, STRCT_DP_DOW, STRCT_DP_DOW_FULL, STRCT_DP_MONTHS, STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_NOTIFICATION_HISTORY_LIMIT, STRCT_PALETTES, STRCT_RAW_ICONS, STRCT_TIME_RANGE_PRESETS, STRCT_WIZARD_DEFAULTS, StrctAccordion, StrctAccordionPanel, StrctAlert, StrctAnnouncer, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctBytesPipe, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCardHeaderActions, StrctCardHeaderMeta, StrctCardHeaderNote, StrctCascadeColumn, StrctCascadeHost, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChart, StrctCheckbox, StrctChips, StrctCode, StrctCodeInline, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctConfirmOutlet, StrctConfirmService, StrctContextMenu, StrctContextMenuTrigger, StrctControlDescription, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatagridActionBarCaption, StrctDatepicker, StrctDatetimePicker, StrctDesc, StrctDescriptionList, StrctDiff, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctDropdownItemAction, StrctDropdownTrigger, StrctDurationPipe, StrctEmptyState, StrctField, StrctFieldGroup, StrctFieldHint, StrctFieldPrefix, StrctFieldSuffix, StrctFile, StrctFilterBar, StrctFlow, StrctFooter, StrctGauge, StrctHeader, StrctHeatmap, StrctHero, StrctHotkeysHelp, StrctHotkeysService, StrctIcon, StrctInlineEdit, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctList, StrctListItem, StrctListItemDescription, StrctListItemLeading, StrctListItemMeta, StrctListItemTrailing, StrctLogViewer, StrctLogin, StrctMenuPanel, StrctMenuService, StrctMenubar, StrctMetricTile, StrctModal, StrctModalContent, StrctNav, StrctNavItem, StrctNotificationCenter, StrctNumber, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPageHeaderTitleMeta, StrctPagination, StrctPassword, StrctPopover, StrctPopoverTrigger, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRatePipe, StrctRating, StrctReorder, StrctReorderItem, StrctRowDetailDef, StrctSearchbox, StrctSectionHeader, StrctSectionHeaderActions, StrctSectionHeaderMeta, StrctSectionMenu, StrctSegmented, StrctSelect, StrctShell, StrctShellService, StrctSiPipe, StrctSignpost, StrctSignpostTrigger, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctSplitButton, StrctSplitter, StrctStack, StrctStackItem, StrctStatusDot, StrctStep, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctTagLeading, StrctThemeService, StrctThemeSwitcher, StrctTimeRangePicker, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctToolbar, StrctToolbarCaption, StrctToolbarSpacer, StrctTooltip, StrctTour, StrctTransfer, StrctTree, StrctTreeNode, StrctTreeSelect, StrctVerticalNav, StrctWatermark, StrctWizard, StrctWizardAside, focusFirstIn, keepTabInside, lockBodyScroll, parseAnsi, provideStrctWizardDefaults, registerStrctIcon, restoreFocus, saveFocusedElement, strctComputeDiff, strctDpPad, strctFormatBytes, strctFormatDuration, strctFormatRate, strctFormatSi, strctValidationIcon, strctValidationTone, unlockBodyScroll };
23614
23751
  //# sourceMappingURL=akcelik-strct.mjs.map