ng-blatui 1.19.0 → 1.20.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.
@@ -5425,6 +5425,254 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
5425
5425
  }]
5426
5426
  }], propDecorators: { max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], scaleTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "scaleTo", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
5427
5427
 
5428
+ /**
5429
+ * An accessible select (combobox + listbox) using the `aria-activedescendant` pattern:
5430
+ * focus stays on the trigger while arrows move the active option. Full keyboard support
5431
+ * (arrows, Home/End, Enter, Escape) and outside-click close. SSR-safe.
5432
+ */
5433
+ class BuiSelect {
5434
+ value = model('', /* @ts-ignore */
5435
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
5436
+ options = input([], /* @ts-ignore */
5437
+ ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
5438
+ placeholder = input('Select…', /* @ts-ignore */
5439
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
5440
+ disabled = input(false, /* @ts-ignore */
5441
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
5442
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
5443
+ listId = inject(_IdGenerator).getId('bui-select-');
5444
+ host = inject(ElementRef);
5445
+ open = signal(false, /* @ts-ignore */
5446
+ ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
5447
+ active = signal(0, /* @ts-ignore */
5448
+ ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
5449
+ selectedLabel = computed(() => this.options().find((option) => option.value === this.value())?.label ?? '', /* @ts-ignore */
5450
+ ...(ngDevMode ? [{ debugName: "selectedLabel" }] : /* istanbul ignore next */ []));
5451
+ computedClass = computed(() => cn('relative block', this.userClass()), /* @ts-ignore */
5452
+ ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
5453
+ toggle() {
5454
+ if (this.open()) {
5455
+ this.close();
5456
+ }
5457
+ else {
5458
+ this.openList();
5459
+ }
5460
+ }
5461
+ select(option) {
5462
+ if (option.disabled) {
5463
+ return;
5464
+ }
5465
+ this.value.set(option.value);
5466
+ this.close();
5467
+ }
5468
+ onKeydown(event) {
5469
+ if (this.disabled()) {
5470
+ return;
5471
+ }
5472
+ if (!this.open()) {
5473
+ if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(event.key)) {
5474
+ event.preventDefault();
5475
+ this.openList();
5476
+ }
5477
+ return;
5478
+ }
5479
+ const options = this.options();
5480
+ switch (event.key) {
5481
+ case 'ArrowDown': {
5482
+ event.preventDefault();
5483
+ this.active.set(Math.min(options.length - 1, this.active() + 1));
5484
+ break;
5485
+ }
5486
+ case 'ArrowUp': {
5487
+ event.preventDefault();
5488
+ this.active.set(Math.max(0, this.active() - 1));
5489
+ break;
5490
+ }
5491
+ case 'Home': {
5492
+ event.preventDefault();
5493
+ this.active.set(0);
5494
+ break;
5495
+ }
5496
+ case 'End': {
5497
+ event.preventDefault();
5498
+ this.active.set(options.length - 1);
5499
+ break;
5500
+ }
5501
+ case 'Enter':
5502
+ case ' ': {
5503
+ event.preventDefault();
5504
+ if (options.length > 0) {
5505
+ this.select(options[this.active()]);
5506
+ }
5507
+ break;
5508
+ }
5509
+ case 'Escape': {
5510
+ event.preventDefault();
5511
+ this.close();
5512
+ break;
5513
+ }
5514
+ default: {
5515
+ break;
5516
+ }
5517
+ }
5518
+ }
5519
+ onDocumentClick(event) {
5520
+ if (this.open() && !this.host.nativeElement.contains(event.target)) {
5521
+ this.close();
5522
+ }
5523
+ }
5524
+ openList() {
5525
+ const current = this.options().findIndex((option) => option.value === this.value());
5526
+ this.active.set(current === -1 ? 0 : current);
5527
+ this.open.set(true);
5528
+ }
5529
+ close() {
5530
+ this.open.set(false);
5531
+ }
5532
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
5533
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiSelect, isStandalone: true, selector: "bui-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "data-slot": "select" }, listeners: { "document:click": "onDocumentClick($event)" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
5534
+ <button
5535
+ type="button"
5536
+ role="combobox"
5537
+ [attr.aria-expanded]="open()"
5538
+ aria-haspopup="listbox"
5539
+ [attr.aria-controls]="listId"
5540
+ [attr.aria-activedescendant]="open() ? listId + '-' + active() : null"
5541
+ [attr.data-placeholder]="selectedLabel() ? null : ''"
5542
+ [disabled]="disabled()"
5543
+ class="flex h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground"
5544
+ (click)="toggle()"
5545
+ (keydown)="onKeydown($event)"
5546
+ >
5547
+ <span class="truncate">{{ selectedLabel() || placeholder() }}</span>
5548
+ <svg
5549
+ viewBox="0 0 24 24"
5550
+ fill="none"
5551
+ stroke="currentColor"
5552
+ stroke-width="2"
5553
+ stroke-linecap="round"
5554
+ stroke-linejoin="round"
5555
+ aria-hidden="true"
5556
+ class="size-4 opacity-50"
5557
+ >
5558
+ <path d="m6 9 6 6 6-6" />
5559
+ </svg>
5560
+ </button>
5561
+ @if (open()) {
5562
+ <ul
5563
+ [id]="listId"
5564
+ role="listbox"
5565
+ class="absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md"
5566
+ >
5567
+ @for (option of options(); track option.value; let i = $index) {
5568
+ <li
5569
+ [id]="listId + '-' + i"
5570
+ role="option"
5571
+ [attr.aria-selected]="option.value === value()"
5572
+ [attr.aria-disabled]="option.disabled ? true : null"
5573
+ class="relative flex cursor-default items-center justify-between gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none"
5574
+ [class]="i === active() ? 'bg-accent text-accent-foreground' : ''"
5575
+ (click)="select(option)"
5576
+ (mouseenter)="active.set(i)"
5577
+ >
5578
+ <span class="truncate">{{ option.label }}</span>
5579
+ @if (option.value === value()) {
5580
+ <svg
5581
+ viewBox="0 0 24 24"
5582
+ fill="none"
5583
+ stroke="currentColor"
5584
+ stroke-width="2"
5585
+ stroke-linecap="round"
5586
+ stroke-linejoin="round"
5587
+ aria-hidden="true"
5588
+ class="size-4"
5589
+ >
5590
+ <path d="M20 6 9 17l-5-5" />
5591
+ </svg>
5592
+ }
5593
+ </li>
5594
+ }
5595
+ </ul>
5596
+ }
5597
+ `, isInline: true });
5598
+ }
5599
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiSelect, decorators: [{
5600
+ type: Component,
5601
+ args: [{
5602
+ selector: 'bui-select',
5603
+ host: {
5604
+ 'data-slot': 'select',
5605
+ '[class]': 'computedClass()',
5606
+ '(document:click)': 'onDocumentClick($event)',
5607
+ },
5608
+ template: `
5609
+ <button
5610
+ type="button"
5611
+ role="combobox"
5612
+ [attr.aria-expanded]="open()"
5613
+ aria-haspopup="listbox"
5614
+ [attr.aria-controls]="listId"
5615
+ [attr.aria-activedescendant]="open() ? listId + '-' + active() : null"
5616
+ [attr.data-placeholder]="selectedLabel() ? null : ''"
5617
+ [disabled]="disabled()"
5618
+ class="flex h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground"
5619
+ (click)="toggle()"
5620
+ (keydown)="onKeydown($event)"
5621
+ >
5622
+ <span class="truncate">{{ selectedLabel() || placeholder() }}</span>
5623
+ <svg
5624
+ viewBox="0 0 24 24"
5625
+ fill="none"
5626
+ stroke="currentColor"
5627
+ stroke-width="2"
5628
+ stroke-linecap="round"
5629
+ stroke-linejoin="round"
5630
+ aria-hidden="true"
5631
+ class="size-4 opacity-50"
5632
+ >
5633
+ <path d="m6 9 6 6 6-6" />
5634
+ </svg>
5635
+ </button>
5636
+ @if (open()) {
5637
+ <ul
5638
+ [id]="listId"
5639
+ role="listbox"
5640
+ class="absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md"
5641
+ >
5642
+ @for (option of options(); track option.value; let i = $index) {
5643
+ <li
5644
+ [id]="listId + '-' + i"
5645
+ role="option"
5646
+ [attr.aria-selected]="option.value === value()"
5647
+ [attr.aria-disabled]="option.disabled ? true : null"
5648
+ class="relative flex cursor-default items-center justify-between gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none"
5649
+ [class]="i === active() ? 'bg-accent text-accent-foreground' : ''"
5650
+ (click)="select(option)"
5651
+ (mouseenter)="active.set(i)"
5652
+ >
5653
+ <span class="truncate">{{ option.label }}</span>
5654
+ @if (option.value === value()) {
5655
+ <svg
5656
+ viewBox="0 0 24 24"
5657
+ fill="none"
5658
+ stroke="currentColor"
5659
+ stroke-width="2"
5660
+ stroke-linecap="round"
5661
+ stroke-linejoin="round"
5662
+ aria-hidden="true"
5663
+ class="size-4"
5664
+ >
5665
+ <path d="M20 6 9 17l-5-5" />
5666
+ </svg>
5667
+ }
5668
+ </li>
5669
+ }
5670
+ </ul>
5671
+ }
5672
+ `,
5673
+ }]
5674
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
5675
+
5428
5676
  /*
5429
5677
  * Public API Surface of ng-blatui
5430
5678
  */
@@ -5433,5 +5681,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
5433
5681
  * Generated bundle index. Do not edit.
5434
5682
  */
5435
5683
 
5436
- export { BuiAccordion, BuiAccordionContent, BuiAccordionItem, BuiAccordionTrigger, BuiAlert, BuiAlertDescription, BuiAlertDialogAction, BuiAlertDialogCancel, BuiAlertDialogContent, BuiAlertDialogDescription, BuiAlertDialogFooter, BuiAlertDialogHeader, BuiAlertDialogTitle, BuiAlertTitle, BuiAspectRatio, BuiAutosizeTextarea, BuiAvatar, BuiAvatarGroup, BuiBadge, BuiBanner, BuiBreadcrumb, BuiBreadcrumbEllipsis, BuiBreadcrumbItem, BuiBreadcrumbLink, BuiBreadcrumbList, BuiBreadcrumbPage, BuiBreadcrumbSeparator, BuiButton, BuiButtonGroup, BuiButtonGroupText, BuiCard, BuiCardAction, BuiCardContent, BuiCardDescription, BuiCardFooter, BuiCardHeader, BuiCardTitle, BuiCheckbox, BuiCodeBlock, BuiCollapsible, BuiCollapsibleContent, BuiCollapsibleTrigger, BuiComparisonTable, BuiContainer, BuiCopyButton, BuiDialogContent, BuiDialogDescription, BuiDialogFooter, BuiDialogHeader, BuiDialogTitle, BuiDotPattern, BuiDropdownMenu, BuiDropdownMenuItem, BuiDropdownMenuLabel, BuiDropdownMenuSeparator, BuiEmpty, BuiEmptyContent, BuiEmptyDescription, BuiEmptyHeader, BuiEmptyMedia, BuiEmptyTitle, BuiField, BuiFieldContent, BuiFieldDescription, BuiFieldError, BuiFieldGroup, BuiFieldLabel, BuiFieldLegend, BuiFieldSeparator, BuiFieldSet, BuiFieldTitle, BuiFlipCard, BuiGridPattern, BuiHoverCard, BuiHoverCardContent, BuiInput, BuiInputGroup, BuiInputGroupAddon, BuiInputGroupButton, BuiInputGroupInput, BuiInputGroupText, BuiItem, BuiItemActions, BuiItemContent, BuiItemDescription, BuiItemGroup, BuiItemMedia, BuiItemTitle, BuiKbd, BuiLabel, BuiMenubar, BuiMenubarTrigger, BuiMeter, BuiPagination, BuiPaginationContent, BuiPaginationEllipsis, BuiPaginationItem, BuiPaginationLink, BuiPopover, BuiPopoverContent, BuiProgress, BuiQuantitySelector, BuiRadioGroup, BuiRadioGroupItem, BuiRating, BuiScrollArea, BuiSegmentedControl, BuiSeparator, BuiSkeleton, BuiSlider, BuiSpinner, BuiSpotlightCard, BuiStat, BuiSwitch, BuiTabList, BuiTabPanel, BuiTabTrigger, BuiTable, BuiTableBody, BuiTableCaption, BuiTableCell, BuiTableContainer, BuiTableFooter, BuiTableHead, BuiTableHeader, BuiTableRow, BuiTabs, BuiTerminal, BuiTextarea, BuiThemeCustomizer, BuiTiltCard, BuiToggle, BuiTooltip, BuiTooltipContent, BuiTypography, BuiVisuallyHidden, THEME_TOKENS, ThemeStore, buttonVariants, cn, toggleVariants };
5684
+ export { BuiAccordion, BuiAccordionContent, BuiAccordionItem, BuiAccordionTrigger, BuiAlert, BuiAlertDescription, BuiAlertDialogAction, BuiAlertDialogCancel, BuiAlertDialogContent, BuiAlertDialogDescription, BuiAlertDialogFooter, BuiAlertDialogHeader, BuiAlertDialogTitle, BuiAlertTitle, BuiAspectRatio, BuiAutosizeTextarea, BuiAvatar, BuiAvatarGroup, BuiBadge, BuiBanner, BuiBreadcrumb, BuiBreadcrumbEllipsis, BuiBreadcrumbItem, BuiBreadcrumbLink, BuiBreadcrumbList, BuiBreadcrumbPage, BuiBreadcrumbSeparator, BuiButton, BuiButtonGroup, BuiButtonGroupText, BuiCard, BuiCardAction, BuiCardContent, BuiCardDescription, BuiCardFooter, BuiCardHeader, BuiCardTitle, BuiCheckbox, BuiCodeBlock, BuiCollapsible, BuiCollapsibleContent, BuiCollapsibleTrigger, BuiComparisonTable, BuiContainer, BuiCopyButton, BuiDialogContent, BuiDialogDescription, BuiDialogFooter, BuiDialogHeader, BuiDialogTitle, BuiDotPattern, BuiDropdownMenu, BuiDropdownMenuItem, BuiDropdownMenuLabel, BuiDropdownMenuSeparator, BuiEmpty, BuiEmptyContent, BuiEmptyDescription, BuiEmptyHeader, BuiEmptyMedia, BuiEmptyTitle, BuiField, BuiFieldContent, BuiFieldDescription, BuiFieldError, BuiFieldGroup, BuiFieldLabel, BuiFieldLegend, BuiFieldSeparator, BuiFieldSet, BuiFieldTitle, BuiFlipCard, BuiGridPattern, BuiHoverCard, BuiHoverCardContent, BuiInput, BuiInputGroup, BuiInputGroupAddon, BuiInputGroupButton, BuiInputGroupInput, BuiInputGroupText, BuiItem, BuiItemActions, BuiItemContent, BuiItemDescription, BuiItemGroup, BuiItemMedia, BuiItemTitle, BuiKbd, BuiLabel, BuiMenubar, BuiMenubarTrigger, BuiMeter, BuiPagination, BuiPaginationContent, BuiPaginationEllipsis, BuiPaginationItem, BuiPaginationLink, BuiPopover, BuiPopoverContent, BuiProgress, BuiQuantitySelector, BuiRadioGroup, BuiRadioGroupItem, BuiRating, BuiScrollArea, BuiSegmentedControl, BuiSelect, BuiSeparator, BuiSkeleton, BuiSlider, BuiSpinner, BuiSpotlightCard, BuiStat, BuiSwitch, BuiTabList, BuiTabPanel, BuiTabTrigger, BuiTable, BuiTableBody, BuiTableCaption, BuiTableCell, BuiTableContainer, BuiTableFooter, BuiTableHead, BuiTableHeader, BuiTableRow, BuiTabs, BuiTerminal, BuiTextarea, BuiThemeCustomizer, BuiTiltCard, BuiToggle, BuiTooltip, BuiTooltipContent, BuiTypography, BuiVisuallyHidden, THEME_TOKENS, ThemeStore, buttonVariants, cn, toggleVariants };
5437
5685
  //# sourceMappingURL=ng-blatui.mjs.map