@basis-ng/primitives 0.0.1-alpha.142 → 0.0.1-alpha.144

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.
@@ -3,7 +3,7 @@ import { input, output, Component, inject, ElementRef, signal, model, computed,
3
3
  import { NgIcon, provideIcons } from '@ng-icons/core';
4
4
  import { lucideX, lucideChevronRight, lucideChevronLeft, lucideLoaderCircle, lucideLoader, lucideGripVertical } from '@ng-icons/lucide';
5
5
  import { GridCellWidget, Grid, GridRow, GridCell } from '@angular/aria/grid';
6
- import { ActiveDescendantKeyManager, CdkTrapFocus } from '@angular/cdk/a11y';
6
+ import { ActiveDescendantKeyManager, CdkTrapFocus, FocusMonitor } from '@angular/cdk/a11y';
7
7
  import * as i1 from '@angular/cdk/listbox';
8
8
  import { CdkOption, CdkListbox } from '@angular/cdk/listbox';
9
9
  import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
@@ -13,7 +13,9 @@ import * as i1$1 from '@angular/cdk/menu';
13
13
  import { CdkMenu, CdkMenuGroup, CdkMenuItem, CdkMenuItemCheckbox, CdkMenuItemRadio, CdkMenuTrigger } from '@angular/cdk/menu';
14
14
  import * as i1$2 from '@angular/cdk/overlay';
15
15
  import { CdkConnectedOverlay, ScrollStrategyOptions, CdkOverlayOrigin, Overlay as Overlay$1 } from '@angular/cdk/overlay';
16
- import * as i1$3 from '@angular/cdk/drag-drop';
16
+ import * as i1$3 from '@angular/aria/tabs';
17
+ import { TabList, Tabs as Tabs$1, Tab as Tab$1 } from '@angular/aria/tabs';
18
+ import * as i1$4 from '@angular/cdk/drag-drop';
17
19
  import { CdkDrag, CdkDragHandle, CdkDropList, CdkDropListGroup } from '@angular/cdk/drag-drop';
18
20
  import { HttpClient } from '@angular/common/http';
19
21
  import { isPlatformBrowser } from '@angular/common';
@@ -3253,43 +3255,32 @@ class Tabs {
3253
3255
  * Query list of Tab child components.
3254
3256
  */
3255
3257
  tabs = contentChildren(Tab, ...(ngDevMode ? [{ debugName: "tabs" }] : []));
3256
- /**
3257
- * Computed index of currently active tab.
3258
- */
3259
- activeIndex = computed(() => {
3260
- const currentValue = this.value()[0];
3261
- return this.tabs().findIndex((tab) => tab.value() === currentValue);
3262
- }, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
3258
+ tabList = inject(TabList);
3263
3259
  constructor() {
3264
- // Sync tab selection with child tabs
3260
+ // Sync external model selection changes back to the underlying aria TabList
3265
3261
  effect(() => {
3266
3262
  const selectedValues = this.value();
3267
- this.tabs().forEach((tab) => {
3268
- tab.setSelected(selectedValues.includes(tab.value()));
3269
- });
3263
+ if (selectedValues.length > 0) {
3264
+ this.tabList.selectedTab.set(selectedValues[0]);
3265
+ }
3266
+ else {
3267
+ this.tabList.selectedTab.set(undefined);
3268
+ }
3270
3269
  });
3271
3270
  }
3272
- /**
3273
- * Move highlight to the previous tab.
3274
- */
3275
- previousTab() {
3276
- const currentIndex = this.activeIndex();
3277
- const tabs = this.tabs();
3278
- if (tabs.length === 0)
3279
- return;
3280
- const newIndex = currentIndex <= 0 ? tabs.length - 1 : currentIndex - 1;
3281
- this.selectTab(tabs[newIndex].value());
3282
- }
3283
- /**
3284
- * Move highlight to the next tab.
3285
- */
3286
- nextTab() {
3287
- const currentIndex = this.activeIndex();
3288
- const tabs = this.tabs();
3289
- if (tabs.length === 0)
3290
- return;
3291
- const newIndex = currentIndex >= tabs.length - 1 ? 0 : currentIndex + 1;
3292
- this.selectTab(tabs[newIndex].value());
3271
+ onSelectionChange(selectedValue) {
3272
+ if (selectedValue !== undefined) {
3273
+ if (this.value()[0] !== selectedValue) {
3274
+ this.value.set([selectedValue]);
3275
+ this.valueChange.emit([selectedValue]);
3276
+ // If a tab is selected via keyboard logic in "follow" mode, trigger an actual click
3277
+ // so that potential bindings like [routerLink] embedded in the tabs still activate naturally.
3278
+ const tab = this.tabs().find((t) => t.value() === selectedValue);
3279
+ if (tab?.el.nativeElement) {
3280
+ tab.el.nativeElement.click();
3281
+ }
3282
+ }
3283
+ }
3293
3284
  }
3294
3285
  /**
3295
3286
  * Select a tab by its value.
@@ -3299,18 +3290,27 @@ class Tabs {
3299
3290
  this.valueChange.emit([tabValue]);
3300
3291
  }
3301
3292
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: Tabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
3302
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.8", type: Tabs, isStandalone: true, selector: "b-tabs", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", valueChange: "valueChange" }, host: { listeners: { "keydown.arrowLeft": "previousTab()", "keydown.arrowRight": "nextTab()" }, properties: { "attr.role": "\"tablist\"" } }, queries: [{ propertyName: "tabs", predicate: Tab, isSignal: true }], ngImport: i0, template: ` <ng-content /> `, isInline: true });
3293
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.8", type: Tabs, isStandalone: true, selector: "b-tabs", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", valueChange: "valueChange" }, host: { attributes: { "selectionMode": "follow" }, listeners: { "selectedTabChange": "onSelectionChange($event)" } }, queries: [{ propertyName: "tabs", predicate: Tab, isSignal: true }], hostDirectives: [{ directive: i1$3.Tabs }, { directive: i1$3.TabList, inputs: ["selectionMode", "selectionMode", "selectedTab", "selectedTab"], outputs: ["selectedTabChange", "selectedTabChange"] }], ngImport: i0, template: ` <ng-content /> `, isInline: true });
3303
3294
  }
3304
3295
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: Tabs, decorators: [{
3305
3296
  type: Component,
3306
3297
  args: [{
3307
3298
  selector: 'b-tabs',
3308
3299
  imports: [],
3300
+ hostDirectives: [
3301
+ {
3302
+ directive: Tabs$1,
3303
+ },
3304
+ {
3305
+ directive: TabList,
3306
+ inputs: ['selectionMode', 'selectedTab'],
3307
+ outputs: ['selectedTabChange'],
3308
+ },
3309
+ ],
3309
3310
  template: ` <ng-content /> `,
3310
3311
  host: {
3311
- '[attr.role]': '"tablist"',
3312
- '(keydown.arrowLeft)': 'previousTab()',
3313
- '(keydown.arrowRight)': 'nextTab()',
3312
+ selectionMode: 'follow',
3313
+ '(selectedTabChange)': 'onSelectionChange($event)',
3314
3314
  },
3315
3315
  }]
3316
3316
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], tabs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => Tab), { isSignal: true }] }] } });
@@ -3322,7 +3322,7 @@ class Tab {
3322
3322
  /**
3323
3323
  * Parent tabs container.
3324
3324
  */
3325
- tabs = inject(Tabs);
3325
+ tabsContainer = inject(Tabs);
3326
3326
  /**
3327
3327
  * Host element reference.
3328
3328
  */
@@ -3331,47 +3331,39 @@ class Tab {
3331
3331
  * Unique value identifying this tab.
3332
3332
  */
3333
3333
  value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
3334
- /**
3335
- * Internal signal tracking selection state.
3336
- */
3337
- selected = signal(false, ...(ngDevMode ? [{ debugName: "selected" }] : []));
3338
- /**
3339
- * Whether this tab is currently selected.
3340
- */
3341
- isSelected = computed(() => this.selected(), ...(ngDevMode ? [{ debugName: "isSelected" }] : []));
3334
+ focusMonitor = inject(FocusMonitor);
3342
3335
  constructor() {
3343
- // Focus this tab when it becomes selected
3344
- effect(() => {
3345
- if (this.isSelected()) {
3346
- this.el.nativeElement.focus();
3347
- }
3348
- });
3336
+ this.focusMonitor.monitor(this.el);
3337
+ }
3338
+ ngOnDestroy() {
3339
+ this.focusMonitor.stopMonitoring(this.el);
3349
3340
  }
3350
3341
  /**
3351
- * Set the selected state of this tab.
3342
+ * Whether this tab is currently selected.
3352
3343
  */
3353
- setSelected(selected) {
3354
- this.selected.set(selected);
3355
- }
3344
+ isSelected = computed(() => this.value() === this.tabsContainer.value()[0], ...(ngDevMode ? [{ debugName: "isSelected" }] : []));
3356
3345
  /**
3357
3346
  * Handle click events to select this tab.
3358
3347
  */
3359
3348
  onClick() {
3360
- this.tabs.selectTab(this.value());
3349
+ this.tabsContainer.selectTab(this.value());
3361
3350
  }
3362
3351
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: Tab, deps: [], target: i0.ɵɵFactoryTarget.Component });
3363
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.8", type: Tab, isStandalone: true, selector: "b-tab", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "onClick()" }, properties: { "attr.role": "\"tab\"", "attr.aria-selected": "isSelected()", "attr.tabindex": "isSelected() ? 0 : -1" } }, ngImport: i0, template: ` <ng-content /> `, isInline: true });
3352
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.8", type: Tab, isStandalone: true, selector: "button[b-tab], [b-tab]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "onClick()" } }, hostDirectives: [{ directive: i1$3.Tab, inputs: ["value", "value"] }], ngImport: i0, template: ` <ng-content /> `, isInline: true });
3364
3353
  }
3365
3354
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: Tab, decorators: [{
3366
3355
  type: Component,
3367
3356
  args: [{
3368
- selector: 'b-tab',
3357
+ selector: 'button[b-tab], [b-tab]',
3369
3358
  imports: [],
3359
+ hostDirectives: [
3360
+ {
3361
+ directive: Tab$1,
3362
+ inputs: ['value'],
3363
+ },
3364
+ ],
3370
3365
  template: ` <ng-content /> `,
3371
3366
  host: {
3372
- '[attr.role]': '"tab"',
3373
- '[attr.aria-selected]': 'isSelected()',
3374
- '[attr.tabindex]': 'isSelected() ? 0 : -1',
3375
3367
  '(click)': 'onClick()',
3376
3368
  },
3377
3369
  }]
@@ -3607,7 +3599,7 @@ class TreeNode {
3607
3599
  provideIcons({
3608
3600
  lucideGripVertical,
3609
3601
  }),
3610
- ], queries: [{ propertyName: "nestedTree", first: true, predicate: Tree, descendants: true, isSignal: true }], hostDirectives: [{ directive: i1$3.CdkDrag, inputs: ["cdkDragDisabled", "disabled"] }], ngImport: i0, template: `
3602
+ ], queries: [{ propertyName: "nestedTree", first: true, predicate: Tree, descendants: true, isSignal: true }], hostDirectives: [{ directive: i1$4.CdkDrag, inputs: ["cdkDragDisabled", "disabled"] }], ngImport: i0, template: `
3611
3603
  <section>
3612
3604
  @if (!isNodeDisabled() && !shouldHideDragHandle()) {
3613
3605
  <ng-icon name="lucideGripVertical" size="16" color="currentColor" cdkDragHandle />
@@ -3792,7 +3784,7 @@ class Tree {
3792
3784
  });
3793
3785
  }
3794
3786
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: Tree, deps: [], target: i0.ɵɵFactoryTarget.Component });
3795
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.8", type: Tree, isStandalone: true, selector: "b-tree", inputs: { draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, closeRecursively: { classPropertyName: "closeRecursively", publicName: "closeRecursively", isSignal: true, isRequired: false, transformFunction: null }, dragOnlyWhenCollapsed: { classPropertyName: "dragOnlyWhenCollapsed", publicName: "dragOnlyWhenCollapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dropEmitter: "dropEmitter" }, host: { listeners: { "cdkDropListDropped": "dropEmitter.emit($event)" } }, queries: [{ propertyName: "nestedNodes", predicate: TreeNode, isSignal: true }], hostDirectives: [{ directive: i1$3.CdkDropList, inputs: ["id", "id", "cdkDropListConnectedTo", "connectedTo"], outputs: ["cdkDropListDropped", "cdkDropListDropped"] }, { directive: i1$3.CdkDropListGroup }], ngImport: i0, template: ` <ng-content /> `, isInline: true });
3787
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.8", type: Tree, isStandalone: true, selector: "b-tree", inputs: { draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, closeRecursively: { classPropertyName: "closeRecursively", publicName: "closeRecursively", isSignal: true, isRequired: false, transformFunction: null }, dragOnlyWhenCollapsed: { classPropertyName: "dragOnlyWhenCollapsed", publicName: "dragOnlyWhenCollapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dropEmitter: "dropEmitter" }, host: { listeners: { "cdkDropListDropped": "dropEmitter.emit($event)" } }, queries: [{ propertyName: "nestedNodes", predicate: TreeNode, isSignal: true }], hostDirectives: [{ directive: i1$4.CdkDropList, inputs: ["id", "id", "cdkDropListConnectedTo", "connectedTo"], outputs: ["cdkDropListDropped", "cdkDropListDropped"] }, { directive: i1$4.CdkDropListGroup }], ngImport: i0, template: ` <ng-content /> `, isInline: true });
3796
3788
  }
3797
3789
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: Tree, decorators: [{
3798
3790
  type: Component,