ng-blatui 1.19.0 → 1.21.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.
- package/fesm2022/ng-blatui.mjs +530 -6
- package/fesm2022/ng-blatui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ng-blatui.d.ts +84 -2
package/fesm2022/ng-blatui.mjs
CHANGED
|
@@ -77,7 +77,7 @@ const SIZES$3 = {
|
|
|
77
77
|
default: 'px-2 py-0.5 text-xs',
|
|
78
78
|
lg: 'px-3 py-1 text-sm [&>svg]:size-3.5',
|
|
79
79
|
};
|
|
80
|
-
const VARIANTS = {
|
|
80
|
+
const VARIANTS$1 = {
|
|
81
81
|
default: 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
|
|
82
82
|
secondary: 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
|
|
83
83
|
destructive: 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
|
@@ -113,16 +113,16 @@ const TONES$2 = {
|
|
|
113
113
|
function brandClass(variant) {
|
|
114
114
|
switch (variant) {
|
|
115
115
|
case 'secondary': {
|
|
116
|
-
return VARIANTS.secondary;
|
|
116
|
+
return VARIANTS$1.secondary;
|
|
117
117
|
}
|
|
118
118
|
case 'destructive': {
|
|
119
|
-
return VARIANTS.destructive;
|
|
119
|
+
return VARIANTS$1.destructive;
|
|
120
120
|
}
|
|
121
121
|
case 'outline': {
|
|
122
|
-
return VARIANTS.outline;
|
|
122
|
+
return VARIANTS$1.outline;
|
|
123
123
|
}
|
|
124
124
|
default: {
|
|
125
|
-
return VARIANTS.default;
|
|
125
|
+
return VARIANTS$1.default;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
}
|
|
@@ -5425,6 +5425,530 @@ 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
|
+
|
|
5676
|
+
const VARIANTS = {
|
|
5677
|
+
primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
5678
|
+
subtle: 'bg-card text-foreground hover:bg-accent hover:text-accent-foreground border',
|
|
5679
|
+
};
|
|
5680
|
+
/**
|
|
5681
|
+
* A floating "scroll to top" button that reveals itself once the page scrolls past
|
|
5682
|
+
* `threshold` px. SSR-safe — the scroll position is only read in the browser.
|
|
5683
|
+
*/
|
|
5684
|
+
class BuiBackToTop {
|
|
5685
|
+
threshold = input(300, /* @ts-ignore */
|
|
5686
|
+
...(ngDevMode ? [{ debugName: "threshold" }] : /* istanbul ignore next */ []));
|
|
5687
|
+
variant = input('primary', /* @ts-ignore */
|
|
5688
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
5689
|
+
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
|
|
5690
|
+
shown = signal(false, /* @ts-ignore */
|
|
5691
|
+
...(ngDevMode ? [{ debugName: "shown" }] : /* istanbul ignore next */ []));
|
|
5692
|
+
variantClass = computed(() => VARIANTS[this.variant()], /* @ts-ignore */
|
|
5693
|
+
...(ngDevMode ? [{ debugName: "variantClass" }] : /* istanbul ignore next */ []));
|
|
5694
|
+
computedClass = computed(() => cn('fixed end-6 bottom-6 z-40 block', this.userClass()), /* @ts-ignore */
|
|
5695
|
+
...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
5696
|
+
constructor() {
|
|
5697
|
+
afterNextRender(() => {
|
|
5698
|
+
this.onScroll();
|
|
5699
|
+
});
|
|
5700
|
+
}
|
|
5701
|
+
onScroll() {
|
|
5702
|
+
this.shown.set(globalThis.scrollY > this.threshold());
|
|
5703
|
+
}
|
|
5704
|
+
toTop() {
|
|
5705
|
+
globalThis.scrollTo({ top: 0, behavior: 'smooth' });
|
|
5706
|
+
}
|
|
5707
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiBackToTop, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5708
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: BuiBackToTop, isStandalone: true, selector: "bui-back-to-top", inputs: { threshold: { classPropertyName: "threshold", publicName: "threshold", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "back-to-top" }, listeners: { "window:scroll": "onScroll()" }, properties: { "hidden": "!shown()", "class": "computedClass()" } }, ngImport: i0, template: `
|
|
5709
|
+
<button
|
|
5710
|
+
type="button"
|
|
5711
|
+
aria-label="Back to top"
|
|
5712
|
+
class="inline-flex size-10 items-center justify-center rounded-full shadow-md transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
|
5713
|
+
[class]="variantClass()"
|
|
5714
|
+
(click)="toTop()"
|
|
5715
|
+
>
|
|
5716
|
+
<svg
|
|
5717
|
+
viewBox="0 0 24 24"
|
|
5718
|
+
fill="none"
|
|
5719
|
+
stroke="currentColor"
|
|
5720
|
+
stroke-width="2"
|
|
5721
|
+
stroke-linecap="round"
|
|
5722
|
+
stroke-linejoin="round"
|
|
5723
|
+
aria-hidden="true"
|
|
5724
|
+
class="size-5"
|
|
5725
|
+
>
|
|
5726
|
+
<path d="m5 12 7-7 7 7" />
|
|
5727
|
+
<path d="M12 19V5" />
|
|
5728
|
+
</svg>
|
|
5729
|
+
</button>
|
|
5730
|
+
`, isInline: true });
|
|
5731
|
+
}
|
|
5732
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiBackToTop, decorators: [{
|
|
5733
|
+
type: Component,
|
|
5734
|
+
args: [{
|
|
5735
|
+
selector: 'bui-back-to-top',
|
|
5736
|
+
host: {
|
|
5737
|
+
'data-slot': 'back-to-top',
|
|
5738
|
+
'[hidden]': '!shown()',
|
|
5739
|
+
'[class]': 'computedClass()',
|
|
5740
|
+
'(window:scroll)': 'onScroll()',
|
|
5741
|
+
},
|
|
5742
|
+
template: `
|
|
5743
|
+
<button
|
|
5744
|
+
type="button"
|
|
5745
|
+
aria-label="Back to top"
|
|
5746
|
+
class="inline-flex size-10 items-center justify-center rounded-full shadow-md transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
|
5747
|
+
[class]="variantClass()"
|
|
5748
|
+
(click)="toTop()"
|
|
5749
|
+
>
|
|
5750
|
+
<svg
|
|
5751
|
+
viewBox="0 0 24 24"
|
|
5752
|
+
fill="none"
|
|
5753
|
+
stroke="currentColor"
|
|
5754
|
+
stroke-width="2"
|
|
5755
|
+
stroke-linecap="round"
|
|
5756
|
+
stroke-linejoin="round"
|
|
5757
|
+
aria-hidden="true"
|
|
5758
|
+
class="size-5"
|
|
5759
|
+
>
|
|
5760
|
+
<path d="m5 12 7-7 7 7" />
|
|
5761
|
+
<path d="M12 19V5" />
|
|
5762
|
+
</svg>
|
|
5763
|
+
</button>
|
|
5764
|
+
`,
|
|
5765
|
+
}]
|
|
5766
|
+
}], ctorParameters: () => [], propDecorators: { threshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "threshold", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
5767
|
+
|
|
5768
|
+
/**
|
|
5769
|
+
* A filterable combobox: a text input (`role="combobox"`, `aria-autocomplete="list"`) over a
|
|
5770
|
+
* filtered listbox, using the `aria-activedescendant` pattern. Full keyboard + outside-click.
|
|
5771
|
+
*/
|
|
5772
|
+
class BuiCombobox {
|
|
5773
|
+
value = model('', /* @ts-ignore */
|
|
5774
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
5775
|
+
options = input([], /* @ts-ignore */
|
|
5776
|
+
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
5777
|
+
placeholder = input('Search…', /* @ts-ignore */
|
|
5778
|
+
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
5779
|
+
disabled = input(false, /* @ts-ignore */
|
|
5780
|
+
...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
5781
|
+
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
|
|
5782
|
+
listId = inject(_IdGenerator).getId('bui-combobox-');
|
|
5783
|
+
host = inject(ElementRef);
|
|
5784
|
+
open = signal(false, /* @ts-ignore */
|
|
5785
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
5786
|
+
active = signal(0, /* @ts-ignore */
|
|
5787
|
+
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
5788
|
+
query = signal('', /* @ts-ignore */
|
|
5789
|
+
...(ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []));
|
|
5790
|
+
selectedLabel = computed(() => this.options().find((option) => option.value === this.value())?.label ?? '', /* @ts-ignore */
|
|
5791
|
+
...(ngDevMode ? [{ debugName: "selectedLabel" }] : /* istanbul ignore next */ []));
|
|
5792
|
+
display = computed(() => (this.open() ? this.query() : this.selectedLabel()), /* @ts-ignore */
|
|
5793
|
+
...(ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ []));
|
|
5794
|
+
filtered = computed(() => {
|
|
5795
|
+
const query = this.query().trim().toLowerCase();
|
|
5796
|
+
return query === ''
|
|
5797
|
+
? this.options()
|
|
5798
|
+
: this.options().filter((option) => option.label.toLowerCase().includes(query));
|
|
5799
|
+
}, /* @ts-ignore */
|
|
5800
|
+
...(ngDevMode ? [{ debugName: "filtered" }] : /* istanbul ignore next */ []));
|
|
5801
|
+
computedClass = computed(() => cn('relative block', this.userClass()), /* @ts-ignore */
|
|
5802
|
+
...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
5803
|
+
onInput(event) {
|
|
5804
|
+
this.query.set(event.target.value);
|
|
5805
|
+
this.active.set(0);
|
|
5806
|
+
this.open.set(true);
|
|
5807
|
+
}
|
|
5808
|
+
openList() {
|
|
5809
|
+
this.query.set('');
|
|
5810
|
+
this.active.set(0);
|
|
5811
|
+
this.open.set(true);
|
|
5812
|
+
}
|
|
5813
|
+
select(option) {
|
|
5814
|
+
this.value.set(option.value);
|
|
5815
|
+
this.query.set('');
|
|
5816
|
+
this.open.set(false);
|
|
5817
|
+
}
|
|
5818
|
+
onKeydown(event) {
|
|
5819
|
+
if (this.disabled()) {
|
|
5820
|
+
return;
|
|
5821
|
+
}
|
|
5822
|
+
if (event.key === 'Escape') {
|
|
5823
|
+
this.open.set(false);
|
|
5824
|
+
return;
|
|
5825
|
+
}
|
|
5826
|
+
if (!this.open() && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
|
|
5827
|
+
event.preventDefault();
|
|
5828
|
+
this.openList();
|
|
5829
|
+
return;
|
|
5830
|
+
}
|
|
5831
|
+
const items = this.filtered();
|
|
5832
|
+
switch (event.key) {
|
|
5833
|
+
case 'ArrowDown': {
|
|
5834
|
+
event.preventDefault();
|
|
5835
|
+
this.active.set(Math.min(items.length - 1, this.active() + 1));
|
|
5836
|
+
break;
|
|
5837
|
+
}
|
|
5838
|
+
case 'ArrowUp': {
|
|
5839
|
+
event.preventDefault();
|
|
5840
|
+
this.active.set(Math.max(0, this.active() - 1));
|
|
5841
|
+
break;
|
|
5842
|
+
}
|
|
5843
|
+
case 'Enter': {
|
|
5844
|
+
if (this.open() && items.length > 0) {
|
|
5845
|
+
event.preventDefault();
|
|
5846
|
+
this.select(items[this.active()]);
|
|
5847
|
+
}
|
|
5848
|
+
break;
|
|
5849
|
+
}
|
|
5850
|
+
default: {
|
|
5851
|
+
break;
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5855
|
+
onDocumentClick(event) {
|
|
5856
|
+
if (!(this.open() && !this.host.nativeElement.contains(event.target))) {
|
|
5857
|
+
return;
|
|
5858
|
+
}
|
|
5859
|
+
this.open.set(false);
|
|
5860
|
+
this.query.set('');
|
|
5861
|
+
}
|
|
5862
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiCombobox, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5863
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiCombobox, isStandalone: true, selector: "bui-combobox", 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": "combobox" }, listeners: { "document:click": "onDocumentClick($event)" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
5864
|
+
<input
|
|
5865
|
+
type="text"
|
|
5866
|
+
role="combobox"
|
|
5867
|
+
aria-autocomplete="list"
|
|
5868
|
+
[attr.aria-expanded]="open()"
|
|
5869
|
+
[attr.aria-controls]="listId"
|
|
5870
|
+
[attr.aria-activedescendant]="open() ? listId + '-' + active() : null"
|
|
5871
|
+
[value]="display()"
|
|
5872
|
+
[placeholder]="placeholder()"
|
|
5873
|
+
[disabled]="disabled()"
|
|
5874
|
+
class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50"
|
|
5875
|
+
(input)="onInput($event)"
|
|
5876
|
+
(focus)="openList()"
|
|
5877
|
+
(keydown)="onKeydown($event)"
|
|
5878
|
+
/>
|
|
5879
|
+
@if (open() && filtered().length > 0) {
|
|
5880
|
+
<ul
|
|
5881
|
+
[id]="listId"
|
|
5882
|
+
role="listbox"
|
|
5883
|
+
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"
|
|
5884
|
+
>
|
|
5885
|
+
@for (option of filtered(); track option.value; let i = $index) {
|
|
5886
|
+
<li
|
|
5887
|
+
[id]="listId + '-' + i"
|
|
5888
|
+
role="option"
|
|
5889
|
+
[attr.aria-selected]="option.value === value()"
|
|
5890
|
+
class="relative flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none"
|
|
5891
|
+
[class]="i === active() ? 'bg-accent text-accent-foreground' : ''"
|
|
5892
|
+
(click)="select(option)"
|
|
5893
|
+
(mouseenter)="active.set(i)"
|
|
5894
|
+
>
|
|
5895
|
+
{{ option.label }}
|
|
5896
|
+
</li>
|
|
5897
|
+
}
|
|
5898
|
+
</ul>
|
|
5899
|
+
}
|
|
5900
|
+
`, isInline: true });
|
|
5901
|
+
}
|
|
5902
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiCombobox, decorators: [{
|
|
5903
|
+
type: Component,
|
|
5904
|
+
args: [{
|
|
5905
|
+
selector: 'bui-combobox',
|
|
5906
|
+
host: {
|
|
5907
|
+
'data-slot': 'combobox',
|
|
5908
|
+
'[class]': 'computedClass()',
|
|
5909
|
+
'(document:click)': 'onDocumentClick($event)',
|
|
5910
|
+
},
|
|
5911
|
+
template: `
|
|
5912
|
+
<input
|
|
5913
|
+
type="text"
|
|
5914
|
+
role="combobox"
|
|
5915
|
+
aria-autocomplete="list"
|
|
5916
|
+
[attr.aria-expanded]="open()"
|
|
5917
|
+
[attr.aria-controls]="listId"
|
|
5918
|
+
[attr.aria-activedescendant]="open() ? listId + '-' + active() : null"
|
|
5919
|
+
[value]="display()"
|
|
5920
|
+
[placeholder]="placeholder()"
|
|
5921
|
+
[disabled]="disabled()"
|
|
5922
|
+
class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50"
|
|
5923
|
+
(input)="onInput($event)"
|
|
5924
|
+
(focus)="openList()"
|
|
5925
|
+
(keydown)="onKeydown($event)"
|
|
5926
|
+
/>
|
|
5927
|
+
@if (open() && filtered().length > 0) {
|
|
5928
|
+
<ul
|
|
5929
|
+
[id]="listId"
|
|
5930
|
+
role="listbox"
|
|
5931
|
+
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"
|
|
5932
|
+
>
|
|
5933
|
+
@for (option of filtered(); track option.value; let i = $index) {
|
|
5934
|
+
<li
|
|
5935
|
+
[id]="listId + '-' + i"
|
|
5936
|
+
role="option"
|
|
5937
|
+
[attr.aria-selected]="option.value === value()"
|
|
5938
|
+
class="relative flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none"
|
|
5939
|
+
[class]="i === active() ? 'bg-accent text-accent-foreground' : ''"
|
|
5940
|
+
(click)="select(option)"
|
|
5941
|
+
(mouseenter)="active.set(i)"
|
|
5942
|
+
>
|
|
5943
|
+
{{ option.label }}
|
|
5944
|
+
</li>
|
|
5945
|
+
}
|
|
5946
|
+
</ul>
|
|
5947
|
+
}
|
|
5948
|
+
`,
|
|
5949
|
+
}]
|
|
5950
|
+
}], 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 }] }] } });
|
|
5951
|
+
|
|
5428
5952
|
/*
|
|
5429
5953
|
* Public API Surface of ng-blatui
|
|
5430
5954
|
*/
|
|
@@ -5433,5 +5957,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
5433
5957
|
* Generated bundle index. Do not edit.
|
|
5434
5958
|
*/
|
|
5435
5959
|
|
|
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 };
|
|
5960
|
+
export { BuiAccordion, BuiAccordionContent, BuiAccordionItem, BuiAccordionTrigger, BuiAlert, BuiAlertDescription, BuiAlertDialogAction, BuiAlertDialogCancel, BuiAlertDialogContent, BuiAlertDialogDescription, BuiAlertDialogFooter, BuiAlertDialogHeader, BuiAlertDialogTitle, BuiAlertTitle, BuiAspectRatio, BuiAutosizeTextarea, BuiAvatar, BuiAvatarGroup, BuiBackToTop, BuiBadge, BuiBanner, BuiBreadcrumb, BuiBreadcrumbEllipsis, BuiBreadcrumbItem, BuiBreadcrumbLink, BuiBreadcrumbList, BuiBreadcrumbPage, BuiBreadcrumbSeparator, BuiButton, BuiButtonGroup, BuiButtonGroupText, BuiCard, BuiCardAction, BuiCardContent, BuiCardDescription, BuiCardFooter, BuiCardHeader, BuiCardTitle, BuiCheckbox, BuiCodeBlock, BuiCollapsible, BuiCollapsibleContent, BuiCollapsibleTrigger, BuiCombobox, 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
5961
|
//# sourceMappingURL=ng-blatui.mjs.map
|