ng-blatui 1.31.0 → 1.32.1
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 +363 -90
- package/fesm2022/ng-blatui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ng-blatui.d.ts +46 -7
package/fesm2022/ng-blatui.mjs
CHANGED
|
@@ -86,6 +86,8 @@ const BUI_DEFAULT_LABELS = {
|
|
|
86
86
|
sonnerDismiss: 'Dismiss notification',
|
|
87
87
|
themeCustomizer: 'Theme customizer',
|
|
88
88
|
treeTableToggle: 'Toggle row',
|
|
89
|
+
treeTableCopy: 'Copy as tree',
|
|
90
|
+
treeTableCopied: 'Copied',
|
|
89
91
|
videoPlay: 'Play video',
|
|
90
92
|
};
|
|
91
93
|
/**
|
|
@@ -1093,7 +1095,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
1093
1095
|
}]
|
|
1094
1096
|
}], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], iconOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOn", required: false }] }], iconOff: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOff", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
1095
1097
|
|
|
1096
|
-
const TRIGGER = '
|
|
1098
|
+
const TRIGGER = 'flex flex-1 cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-default disabled:opacity-50 [&>svg]:pointer-events-none [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:translate-y-0.5 [&>svg]:text-muted-foreground [&>svg]:transition-transform [&>svg]:duration-200 [&[aria-expanded=true]>svg]:rotate-180';
|
|
1097
1099
|
class BuiAccordion {
|
|
1098
1100
|
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
|
|
1099
1101
|
computedClass = computed(() => cn('w-full', this.userClass()), /* @ts-ignore */
|
|
@@ -3772,7 +3774,9 @@ class BuiPopover {
|
|
|
3772
3774
|
.withPositions([POPOVER_POSITIONS[side], POPOVER_POSITIONS[POPOVER_FALLBACK[side]]]);
|
|
3773
3775
|
const overlayReference = this.overlay.create({
|
|
3774
3776
|
positionStrategy,
|
|
3775
|
-
|
|
3777
|
+
// Close (not reposition) on scroll, so the popover doesn't hang detached over the page
|
|
3778
|
+
// once its trigger scrolls out of view.
|
|
3779
|
+
scrollStrategy: this.overlay.scrollStrategies.close(),
|
|
3776
3780
|
});
|
|
3777
3781
|
overlayReference.attach(new TemplatePortal(this.content(), this.viewContainerRef));
|
|
3778
3782
|
overlayReference.outsidePointerEvents().subscribe((event) => {
|
|
@@ -5366,8 +5370,15 @@ class BuiDropdownMenu {
|
|
|
5366
5370
|
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
|
|
5367
5371
|
computedClass = computed(() => cn('absolute z-50 mt-1 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md', this.userClass()), /* @ts-ignore */
|
|
5368
5372
|
...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
5373
|
+
// The menu is absolutely anchored to its trigger; once the page scrolls it would otherwise
|
|
5374
|
+
// drift across the layout (e.g. over a sticky navbar). Closing on scroll matches native menus.
|
|
5375
|
+
onScroll() {
|
|
5376
|
+
if (this.menu.visible()) {
|
|
5377
|
+
this.menu.close();
|
|
5378
|
+
}
|
|
5379
|
+
}
|
|
5369
5380
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiDropdownMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
5370
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiDropdownMenu, isStandalone: true, selector: "[buiDropdownMenu]", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "dropdown-menu" }, properties: { "hidden": "!menu.visible()", "class": "computedClass()" } }, ngImport: i0 });
|
|
5381
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiDropdownMenu, isStandalone: true, selector: "[buiDropdownMenu]", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "dropdown-menu" }, listeners: { "window:scroll": "onScroll()" }, properties: { "hidden": "!menu.visible()", "class": "computedClass()" } }, ngImport: i0 });
|
|
5371
5382
|
}
|
|
5372
5383
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiDropdownMenu, decorators: [{
|
|
5373
5384
|
type: Directive,
|
|
@@ -5377,6 +5388,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
5377
5388
|
'data-slot': 'dropdown-menu',
|
|
5378
5389
|
'[hidden]': '!menu.visible()',
|
|
5379
5390
|
'[class]': 'computedClass()',
|
|
5391
|
+
'(window:scroll)': 'onScroll()',
|
|
5380
5392
|
},
|
|
5381
5393
|
}]
|
|
5382
5394
|
}], propDecorators: { userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
@@ -5428,11 +5440,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
5428
5440
|
* `ngMenuTrigger` opening a `ngMenu` (style the menus with `buiDropdownMenu` /
|
|
5429
5441
|
* `buiDropdownMenuItem`). `MenuBar` is re-exported from `ng-blatui`.
|
|
5430
5442
|
*
|
|
5443
|
+
* Wrap each trigger + its menu in a `relative` element so the menu anchors under its own
|
|
5444
|
+
* trigger (otherwise the absolutely-positioned panel lands over the bar itself).
|
|
5445
|
+
*
|
|
5431
5446
|
* ```html
|
|
5432
5447
|
* <div ngMenuBar buiMenubar>
|
|
5433
|
-
* <
|
|
5434
|
-
*
|
|
5435
|
-
* <div
|
|
5448
|
+
* <div class="relative">
|
|
5449
|
+
* <button ngMenuTrigger [menu]="file" buiMenubarTrigger>File</button>
|
|
5450
|
+
* <div ngMenu #file="ngMenu" buiDropdownMenu>
|
|
5451
|
+
* <div ngMenuItem value="new" buiDropdownMenuItem>New</div>
|
|
5452
|
+
* </div>
|
|
5436
5453
|
* </div>
|
|
5437
5454
|
* </div>
|
|
5438
5455
|
* ```
|
|
@@ -6838,11 +6855,24 @@ class BuiCombobox {
|
|
|
6838
6855
|
[disabled]="disabled()"
|
|
6839
6856
|
[readonly]="!searchable()"
|
|
6840
6857
|
[class.cursor-pointer]="!searchable()"
|
|
6841
|
-
class="flex h-9 w-full rounded-md border border-input bg-transparent
|
|
6858
|
+
class="flex h-9 w-full rounded-md border border-input bg-transparent py-2 ps-3 pe-9 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"
|
|
6842
6859
|
(input)="onInput($event)"
|
|
6843
6860
|
(focus)="openList()"
|
|
6844
6861
|
(keydown)="onKeydown($event)"
|
|
6845
6862
|
/>
|
|
6863
|
+
<svg
|
|
6864
|
+
viewBox="0 0 24 24"
|
|
6865
|
+
fill="none"
|
|
6866
|
+
stroke="currentColor"
|
|
6867
|
+
stroke-width="2"
|
|
6868
|
+
stroke-linecap="round"
|
|
6869
|
+
stroke-linejoin="round"
|
|
6870
|
+
aria-hidden="true"
|
|
6871
|
+
class="pointer-events-none absolute end-3 top-[1.125rem] size-4 -translate-y-1/2 text-muted-foreground transition-transform"
|
|
6872
|
+
[class.rotate-180]="open()"
|
|
6873
|
+
>
|
|
6874
|
+
<path d="m6 9 6 6 6-6" />
|
|
6875
|
+
</svg>
|
|
6846
6876
|
@if (open() && filtered().length > 0) {
|
|
6847
6877
|
<ul
|
|
6848
6878
|
[id]="listId"
|
|
@@ -6922,11 +6952,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
6922
6952
|
[disabled]="disabled()"
|
|
6923
6953
|
[readonly]="!searchable()"
|
|
6924
6954
|
[class.cursor-pointer]="!searchable()"
|
|
6925
|
-
class="flex h-9 w-full rounded-md border border-input bg-transparent
|
|
6955
|
+
class="flex h-9 w-full rounded-md border border-input bg-transparent py-2 ps-3 pe-9 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"
|
|
6926
6956
|
(input)="onInput($event)"
|
|
6927
6957
|
(focus)="openList()"
|
|
6928
6958
|
(keydown)="onKeydown($event)"
|
|
6929
6959
|
/>
|
|
6960
|
+
<svg
|
|
6961
|
+
viewBox="0 0 24 24"
|
|
6962
|
+
fill="none"
|
|
6963
|
+
stroke="currentColor"
|
|
6964
|
+
stroke-width="2"
|
|
6965
|
+
stroke-linecap="round"
|
|
6966
|
+
stroke-linejoin="round"
|
|
6967
|
+
aria-hidden="true"
|
|
6968
|
+
class="pointer-events-none absolute end-3 top-[1.125rem] size-4 -translate-y-1/2 text-muted-foreground transition-transform"
|
|
6969
|
+
[class.rotate-180]="open()"
|
|
6970
|
+
>
|
|
6971
|
+
<path d="m6 9 6 6 6-6" />
|
|
6972
|
+
</svg>
|
|
6930
6973
|
@if (open() && filtered().length > 0) {
|
|
6931
6974
|
<ul
|
|
6932
6975
|
[id]="listId"
|
|
@@ -11283,6 +11326,12 @@ class BuiConfetti {
|
|
|
11283
11326
|
/** Horizontal spread factor of the burst. */
|
|
11284
11327
|
spread = input(70, /* @ts-ignore */
|
|
11285
11328
|
...(ngDevMode ? [{ debugName: "spread" }] : /* istanbul ignore next */ []));
|
|
11329
|
+
/** Direction the particles fly out from the origin. */
|
|
11330
|
+
direction = input('down', /* @ts-ignore */
|
|
11331
|
+
...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
|
|
11332
|
+
/** Rain confetti across the whole viewport instead of bursting from the trigger. */
|
|
11333
|
+
fullscreen = input(false, /* @ts-ignore */
|
|
11334
|
+
...(ngDevMode ? [{ debugName: "fullscreen" }] : /* istanbul ignore next */ []));
|
|
11286
11335
|
/** Particle colours; defaults to the built-in palette. */
|
|
11287
11336
|
colors = input(null, /* @ts-ignore */
|
|
11288
11337
|
...(ngDevMode ? [{ debugName: "colors" }] : /* istanbul ignore next */ []));
|
|
@@ -11293,18 +11342,25 @@ class BuiConfetti {
|
|
|
11293
11342
|
seq = 0;
|
|
11294
11343
|
computedClass = computed(() => cn('relative inline-block', this.userClass()), /* @ts-ignore */
|
|
11295
11344
|
...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
11345
|
+
// Fullscreen rains over a fixed, viewport-covering layer; otherwise particles burst from the
|
|
11346
|
+
// trigger's centre (a zero-size anchor at 50%/50%).
|
|
11347
|
+
layerClass = computed(() => this.fullscreen()
|
|
11348
|
+
? 'pointer-events-none fixed inset-0 z-[100]'
|
|
11349
|
+
: 'pointer-events-none absolute top-1/2 left-1/2 size-0', /* @ts-ignore */
|
|
11350
|
+
...(ngDevMode ? [{ debugName: "layerClass" }] : /* istanbul ignore next */ []));
|
|
11296
11351
|
fire() {
|
|
11297
11352
|
const colors = this.colors() ?? PALETTE$1;
|
|
11353
|
+
const isFullscreen = this.fullscreen();
|
|
11354
|
+
const direction = this.direction();
|
|
11298
11355
|
const batch = Array.from({ length: this.count() }, () => {
|
|
11299
|
-
const
|
|
11300
|
-
const dy = 80 + Math.random() * 120;
|
|
11301
|
-
const rot = Math.random() * 720 - 360;
|
|
11356
|
+
const rot = (Math.random() * 720 - 360).toFixed(0);
|
|
11302
11357
|
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
11303
|
-
const delay = (Math.random() * 0.
|
|
11358
|
+
const delay = (Math.random() * 0.15).toFixed(2);
|
|
11304
11359
|
this.seq += 1;
|
|
11360
|
+
const motion = isFullscreen ? this.rain() : this.burst(direction);
|
|
11305
11361
|
return {
|
|
11306
11362
|
id: this.seq,
|
|
11307
|
-
style:
|
|
11363
|
+
style: `${motion}--rot:${rot}deg;background:${color};animation-delay:${delay}s`,
|
|
11308
11364
|
};
|
|
11309
11365
|
});
|
|
11310
11366
|
this.particles.set(batch);
|
|
@@ -11313,7 +11369,49 @@ class BuiConfetti {
|
|
|
11313
11369
|
}
|
|
11314
11370
|
this.timer = setTimeout(() => {
|
|
11315
11371
|
this.particles.set([]);
|
|
11316
|
-
}, 1200);
|
|
11372
|
+
}, isFullscreen ? 2600 : 1200);
|
|
11373
|
+
}
|
|
11374
|
+
/** Translation vars for a burst from the origin, by direction. */
|
|
11375
|
+
burst(direction) {
|
|
11376
|
+
const spread = this.spread();
|
|
11377
|
+
const rand = Math.random;
|
|
11378
|
+
let dx;
|
|
11379
|
+
let dy;
|
|
11380
|
+
switch (direction) {
|
|
11381
|
+
case 'up': {
|
|
11382
|
+
dx = (rand() - 0.5) * spread * 4;
|
|
11383
|
+
dy = -(80 + rand() * 120);
|
|
11384
|
+
break;
|
|
11385
|
+
}
|
|
11386
|
+
case 'left': {
|
|
11387
|
+
dx = -(100 + rand() * spread * 3);
|
|
11388
|
+
dy = (rand() - 0.5) * spread * 2;
|
|
11389
|
+
break;
|
|
11390
|
+
}
|
|
11391
|
+
case 'right': {
|
|
11392
|
+
dx = 100 + rand() * spread * 3;
|
|
11393
|
+
dy = (rand() - 0.5) * spread * 2;
|
|
11394
|
+
break;
|
|
11395
|
+
}
|
|
11396
|
+
case 'radial': {
|
|
11397
|
+
const angle = rand() * Math.PI * 2;
|
|
11398
|
+
const distance = 80 + rand() * 120;
|
|
11399
|
+
dx = Math.cos(angle) * distance;
|
|
11400
|
+
dy = Math.sin(angle) * distance;
|
|
11401
|
+
break;
|
|
11402
|
+
}
|
|
11403
|
+
default: {
|
|
11404
|
+
dx = (rand() - 0.5) * spread * 4;
|
|
11405
|
+
dy = 80 + rand() * 120;
|
|
11406
|
+
}
|
|
11407
|
+
}
|
|
11408
|
+
return `--dx:${dx.toFixed(0)}px;--dy:${dy.toFixed(0)}px;`;
|
|
11409
|
+
}
|
|
11410
|
+
/** Position + fall vars for a particle raining from the top of the viewport. */
|
|
11411
|
+
rain() {
|
|
11412
|
+
const startX = (Math.random() * 100).toFixed(2);
|
|
11413
|
+
const drift = ((Math.random() - 0.5) * 160).toFixed(0);
|
|
11414
|
+
return `left:${startX}vw;top:-5vh;--dx:${drift}px;--dy:110vh;animation-duration:2.4s;`;
|
|
11317
11415
|
}
|
|
11318
11416
|
ngOnDestroy() {
|
|
11319
11417
|
if (this.timer) {
|
|
@@ -11321,7 +11419,7 @@ class BuiConfetti {
|
|
|
11321
11419
|
}
|
|
11322
11420
|
}
|
|
11323
11421
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiConfetti, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11324
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiConfetti, isStandalone: true, selector: "bui-confetti", inputs: { count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, spread: { classPropertyName: "spread", publicName: "spread", isSignal: true, isRequired: false, transformFunction: null }, colors: { classPropertyName: "colors", publicName: "colors", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "confetti" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
11422
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiConfetti, isStandalone: true, selector: "bui-confetti", inputs: { count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, spread: { classPropertyName: "spread", publicName: "spread", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, fullscreen: { classPropertyName: "fullscreen", publicName: "fullscreen", isSignal: true, isRequired: false, transformFunction: null }, colors: { classPropertyName: "colors", publicName: "colors", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "confetti" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
11325
11423
|
<span (click)="fire()" (keydown.enter)="fire()" (keydown.space)="fire()">
|
|
11326
11424
|
<ng-content>
|
|
11327
11425
|
<button
|
|
@@ -11332,7 +11430,7 @@ class BuiConfetti {
|
|
|
11332
11430
|
</button>
|
|
11333
11431
|
</ng-content>
|
|
11334
11432
|
</span>
|
|
11335
|
-
<div class="
|
|
11433
|
+
<div [class]="layerClass()" aria-hidden="true">
|
|
11336
11434
|
@for (particle of particles(); track particle.id) {
|
|
11337
11435
|
<span
|
|
11338
11436
|
class="bui-confetti-particle absolute size-2 rounded-sm"
|
|
@@ -11355,7 +11453,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
11355
11453
|
</button>
|
|
11356
11454
|
</ng-content>
|
|
11357
11455
|
</span>
|
|
11358
|
-
<div class="
|
|
11456
|
+
<div [class]="layerClass()" aria-hidden="true">
|
|
11359
11457
|
@for (particle of particles(); track particle.id) {
|
|
11360
11458
|
<span
|
|
11361
11459
|
class="bui-confetti-particle absolute size-2 rounded-sm"
|
|
@@ -11364,7 +11462,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
11364
11462
|
}
|
|
11365
11463
|
</div>
|
|
11366
11464
|
`, styles: ["@keyframes bui-confetti-fall{to{transform:translate(var(--dx),var(--dy)) rotate(var(--rot));opacity:0}}.bui-confetti-particle{animation:bui-confetti-fall 1s ease-out forwards}@media(prefers-reduced-motion:reduce){.bui-confetti-particle{animation:none;opacity:0}}\n"] }]
|
|
11367
|
-
}], propDecorators: { count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], spread: [{ type: i0.Input, args: [{ isSignal: true, alias: "spread", required: false }] }], colors: [{ type: i0.Input, args: [{ isSignal: true, alias: "colors", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
11465
|
+
}], propDecorators: { count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], spread: [{ type: i0.Input, args: [{ isSignal: true, alias: "spread", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], fullscreen: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullscreen", required: false }] }], colors: [{ type: i0.Input, args: [{ isSignal: true, alias: "colors", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
11368
11466
|
|
|
11369
11467
|
/** A step indicator. The `value` (1-based) marks the active step. Use `li[buiStepperItem]`. */
|
|
11370
11468
|
class BuiStepper {
|
|
@@ -12839,7 +12937,7 @@ class BuiAudioPlayer {
|
|
|
12839
12937
|
...(ngDevMode ? [{ debugName: "duration" }] : /* istanbul ignore next */ []));
|
|
12840
12938
|
muted = signal(false, /* @ts-ignore */
|
|
12841
12939
|
...(ngDevMode ? [{ debugName: "muted" }] : /* istanbul ignore next */ []));
|
|
12842
|
-
computedClass = computed(() => cn('flex items-center gap-
|
|
12940
|
+
computedClass = computed(() => cn('flex min-w-0 items-center gap-2 rounded-lg border bg-card p-2 sm:gap-3 sm:p-3', this.userClass()), /* @ts-ignore */
|
|
12843
12941
|
...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
12844
12942
|
toggle() {
|
|
12845
12943
|
const element = this.a()?.nativeElement;
|
|
@@ -12930,7 +13028,7 @@ class BuiAudioPlayer {
|
|
|
12930
13028
|
step="0.1"
|
|
12931
13029
|
[max]="duration() || 0"
|
|
12932
13030
|
[value]="current()"
|
|
12933
|
-
class="h-1 flex-1 accent-primary"
|
|
13031
|
+
class="h-1 min-w-0 flex-1 accent-primary"
|
|
12934
13032
|
[attr.aria-label]="seekText()"
|
|
12935
13033
|
(input)="seek($event)"
|
|
12936
13034
|
/>
|
|
@@ -13002,7 +13100,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
13002
13100
|
step="0.1"
|
|
13003
13101
|
[max]="duration() || 0"
|
|
13004
13102
|
[value]="current()"
|
|
13005
|
-
class="h-1 flex-1 accent-primary"
|
|
13103
|
+
class="h-1 min-w-0 flex-1 accent-primary"
|
|
13006
13104
|
[attr.aria-label]="seekText()"
|
|
13007
13105
|
(input)="seek($event)"
|
|
13008
13106
|
/>
|
|
@@ -13666,12 +13764,20 @@ class BuiNotificationCenter {
|
|
|
13666
13764
|
unreadText = buiLabel('notificationCenterUnread', this.unreadLabel);
|
|
13667
13765
|
markAllReadText = buiLabel('notificationCenterMarkAllRead', this.markAllReadLabel);
|
|
13668
13766
|
emptyText = buiLabel('notificationCenterEmpty', this.emptyLabel);
|
|
13767
|
+
host = inject(ElementRef);
|
|
13669
13768
|
markedRead = signal(new Set(), /* @ts-ignore */
|
|
13670
13769
|
...(ngDevMode ? [{ debugName: "markedRead" }] : /* istanbul ignore next */ []));
|
|
13671
13770
|
unread = computed(() => this.notifications().filter((_, index) => !this.isRead(index)).length, /* @ts-ignore */
|
|
13672
13771
|
...(ngDevMode ? [{ debugName: "unread" }] : /* istanbul ignore next */ []));
|
|
13673
13772
|
computedClass = computed(() => cn('relative inline-block', this.userClass()), /* @ts-ignore */
|
|
13674
13773
|
...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
13774
|
+
// Close when a click lands outside the bell + panel. The trigger's own click is contained in
|
|
13775
|
+
// the host, so it toggles open without this handler immediately closing it again.
|
|
13776
|
+
onDocumentClick(event) {
|
|
13777
|
+
if (this.open() && !this.host.nativeElement.contains(event.target)) {
|
|
13778
|
+
this.open.set(false);
|
|
13779
|
+
}
|
|
13780
|
+
}
|
|
13675
13781
|
isRead(index) {
|
|
13676
13782
|
return this.markedRead().has(index) || (this.notifications()[index]?.read ?? false);
|
|
13677
13783
|
}
|
|
@@ -13679,7 +13785,7 @@ class BuiNotificationCenter {
|
|
|
13679
13785
|
this.markedRead.set(new Set(this.notifications().map((_, index) => index)));
|
|
13680
13786
|
}
|
|
13681
13787
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiNotificationCenter, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13682
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiNotificationCenter, isStandalone: true, selector: "bui-notification-center", inputs: { notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, unreadLabel: { classPropertyName: "unreadLabel", publicName: "unreadLabel", isSignal: true, isRequired: false, transformFunction: null }, markAllReadLabel: { classPropertyName: "markAllReadLabel", publicName: "markAllReadLabel", isSignal: true, isRequired: false, transformFunction: null }, emptyLabel: { classPropertyName: "emptyLabel", publicName: "emptyLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "notification-center" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
13788
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiNotificationCenter, isStandalone: true, selector: "bui-notification-center", inputs: { notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, unreadLabel: { classPropertyName: "unreadLabel", publicName: "unreadLabel", isSignal: true, isRequired: false, transformFunction: null }, markAllReadLabel: { classPropertyName: "markAllReadLabel", publicName: "markAllReadLabel", isSignal: true, isRequired: false, transformFunction: null }, emptyLabel: { classPropertyName: "emptyLabel", publicName: "emptyLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "notification-center" }, listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "open.set(false)", "window:scroll": "open.set(false)" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
13683
13789
|
<button
|
|
13684
13790
|
type="button"
|
|
13685
13791
|
class="relative inline-flex size-9 items-center justify-center rounded-md border border-input hover:bg-accent"
|
|
@@ -13754,7 +13860,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
13754
13860
|
type: Component,
|
|
13755
13861
|
args: [{
|
|
13756
13862
|
selector: 'bui-notification-center',
|
|
13757
|
-
host: {
|
|
13863
|
+
host: {
|
|
13864
|
+
'data-slot': 'notification-center',
|
|
13865
|
+
'[class]': 'computedClass()',
|
|
13866
|
+
'(document:click)': 'onDocumentClick($event)',
|
|
13867
|
+
'(document:keydown.escape)': 'open.set(false)',
|
|
13868
|
+
'(window:scroll)': 'open.set(false)',
|
|
13869
|
+
},
|
|
13758
13870
|
template: `
|
|
13759
13871
|
<button
|
|
13760
13872
|
type="button"
|
|
@@ -14586,7 +14698,21 @@ class BuiTreeTable {
|
|
|
14586
14698
|
/** Accessible label for the expand/collapse toggle button. */
|
|
14587
14699
|
toggleLabel = input(/* @ts-ignore */
|
|
14588
14700
|
...(ngDevMode ? [undefined, { debugName: "toggleLabel" }] : /* istanbul ignore next */ []));
|
|
14701
|
+
/** Show a button that copies the full hierarchy as a markdown ASCII tree. */
|
|
14702
|
+
copyable = input(false, /* @ts-ignore */
|
|
14703
|
+
...(ngDevMode ? [{ debugName: "copyable" }] : /* istanbul ignore next */ []));
|
|
14704
|
+
/** Label override for the copy button (idle state). */
|
|
14705
|
+
copyLabel = input(/* @ts-ignore */
|
|
14706
|
+
...(ngDevMode ? [undefined, { debugName: "copyLabel" }] : /* istanbul ignore next */ []));
|
|
14707
|
+
/** Label override for the copy button after copying. */
|
|
14708
|
+
copiedLabel = input(/* @ts-ignore */
|
|
14709
|
+
...(ngDevMode ? [undefined, { debugName: "copiedLabel" }] : /* istanbul ignore next */ []));
|
|
14589
14710
|
toggleText = buiLabel('treeTableToggle', this.toggleLabel);
|
|
14711
|
+
copyText = buiLabel('treeTableCopy', this.copyLabel);
|
|
14712
|
+
copiedText = buiLabel('treeTableCopied', this.copiedLabel);
|
|
14713
|
+
copied = signal(false, /* @ts-ignore */
|
|
14714
|
+
...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
|
|
14715
|
+
copiedTimer;
|
|
14590
14716
|
overrides = signal(new Map(), /* @ts-ignore */
|
|
14591
14717
|
...(ngDevMode ? [{ debugName: "overrides" }] : /* istanbul ignore next */ []));
|
|
14592
14718
|
defaults = computed(() => {
|
|
@@ -14631,6 +14757,47 @@ class BuiTreeTable {
|
|
|
14631
14757
|
next.set(path, !this.isOpen(path));
|
|
14632
14758
|
this.overrides.set(next);
|
|
14633
14759
|
}
|
|
14760
|
+
/**
|
|
14761
|
+
* Render the full row hierarchy as a markdown ASCII tree (`├──`/`└──`), using the first
|
|
14762
|
+
* column's value as each node's label and a trailing `/` for rows that have children.
|
|
14763
|
+
*/
|
|
14764
|
+
toMarkdownTree() {
|
|
14765
|
+
const key = this.columns()[0]?.key ?? '';
|
|
14766
|
+
const lines = [];
|
|
14767
|
+
const render = (rows, prefix, isRoot) => {
|
|
14768
|
+
for (const [index, row] of rows.entries()) {
|
|
14769
|
+
const children = row.children ?? [];
|
|
14770
|
+
const hasChildren = children.length > 0;
|
|
14771
|
+
const label = this.cell(row, key) + (hasChildren ? '/' : '');
|
|
14772
|
+
if (isRoot) {
|
|
14773
|
+
lines.push(label);
|
|
14774
|
+
if (hasChildren) {
|
|
14775
|
+
render(children, '', false);
|
|
14776
|
+
}
|
|
14777
|
+
continue;
|
|
14778
|
+
}
|
|
14779
|
+
const isLast = index === rows.length - 1;
|
|
14780
|
+
lines.push(`${prefix}${isLast ? '└── ' : '├── '}${label}`);
|
|
14781
|
+
if (hasChildren) {
|
|
14782
|
+
const childIndent = isLast ? ' '.repeat(4) : `│${' '.repeat(3)}`;
|
|
14783
|
+
render(children, prefix + childIndent, false);
|
|
14784
|
+
}
|
|
14785
|
+
}
|
|
14786
|
+
};
|
|
14787
|
+
render(this.rows(), '', true);
|
|
14788
|
+
return lines.join('\n');
|
|
14789
|
+
}
|
|
14790
|
+
copyTree() {
|
|
14791
|
+
void navigator.clipboard.writeText(this.toMarkdownTree());
|
|
14792
|
+
this.copied.set(true);
|
|
14793
|
+
clearTimeout(this.copiedTimer);
|
|
14794
|
+
this.copiedTimer = setTimeout(() => {
|
|
14795
|
+
this.copied.set(false);
|
|
14796
|
+
}, 1500);
|
|
14797
|
+
}
|
|
14798
|
+
ngOnDestroy() {
|
|
14799
|
+
clearTimeout(this.copiedTimer);
|
|
14800
|
+
}
|
|
14634
14801
|
alignClass(align) {
|
|
14635
14802
|
return ALIGN$2[align ?? 'left'];
|
|
14636
14803
|
}
|
|
@@ -14645,7 +14812,47 @@ class BuiTreeTable {
|
|
|
14645
14812
|
return '';
|
|
14646
14813
|
}
|
|
14647
14814
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiTreeTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14648
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiTreeTable, isStandalone: true, selector: "bui-tree-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, toggleLabel: { classPropertyName: "toggleLabel", publicName: "toggleLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "tree-table" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
14815
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiTreeTable, isStandalone: true, selector: "bui-tree-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, toggleLabel: { classPropertyName: "toggleLabel", publicName: "toggleLabel", isSignal: true, isRequired: false, transformFunction: null }, copyable: { classPropertyName: "copyable", publicName: "copyable", isSignal: true, isRequired: false, transformFunction: null }, copyLabel: { classPropertyName: "copyLabel", publicName: "copyLabel", isSignal: true, isRequired: false, transformFunction: null }, copiedLabel: { classPropertyName: "copiedLabel", publicName: "copiedLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "tree-table" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
14816
|
+
@if (copyable()) {
|
|
14817
|
+
<div class="mb-2 flex justify-end">
|
|
14818
|
+
<button
|
|
14819
|
+
type="button"
|
|
14820
|
+
class="inline-flex items-center gap-1.5 rounded-md border border-input px-2.5 py-1 text-xs font-medium hover:bg-accent"
|
|
14821
|
+
(click)="copyTree()"
|
|
14822
|
+
>
|
|
14823
|
+
@if (copied()) {
|
|
14824
|
+
<svg
|
|
14825
|
+
class="size-3.5 text-emerald-500"
|
|
14826
|
+
viewBox="0 0 24 24"
|
|
14827
|
+
fill="none"
|
|
14828
|
+
stroke="currentColor"
|
|
14829
|
+
stroke-width="2"
|
|
14830
|
+
stroke-linecap="round"
|
|
14831
|
+
stroke-linejoin="round"
|
|
14832
|
+
aria-hidden="true"
|
|
14833
|
+
>
|
|
14834
|
+
<path d="M20 6 9 17l-5-5" />
|
|
14835
|
+
</svg>
|
|
14836
|
+
{{ copiedText() }}
|
|
14837
|
+
} @else {
|
|
14838
|
+
<svg
|
|
14839
|
+
class="size-3.5"
|
|
14840
|
+
viewBox="0 0 24 24"
|
|
14841
|
+
fill="none"
|
|
14842
|
+
stroke="currentColor"
|
|
14843
|
+
stroke-width="2"
|
|
14844
|
+
stroke-linecap="round"
|
|
14845
|
+
stroke-linejoin="round"
|
|
14846
|
+
aria-hidden="true"
|
|
14847
|
+
>
|
|
14848
|
+
<rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
|
|
14849
|
+
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
|
|
14850
|
+
</svg>
|
|
14851
|
+
{{ copyText() }}
|
|
14852
|
+
}
|
|
14853
|
+
</button>
|
|
14854
|
+
</div>
|
|
14855
|
+
}
|
|
14649
14856
|
<table class="w-full text-sm">
|
|
14650
14857
|
<thead>
|
|
14651
14858
|
<tr class="border-b">
|
|
@@ -14708,6 +14915,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
14708
14915
|
selector: 'bui-tree-table',
|
|
14709
14916
|
host: { 'data-slot': 'tree-table', '[class]': 'computedClass()' },
|
|
14710
14917
|
template: `
|
|
14918
|
+
@if (copyable()) {
|
|
14919
|
+
<div class="mb-2 flex justify-end">
|
|
14920
|
+
<button
|
|
14921
|
+
type="button"
|
|
14922
|
+
class="inline-flex items-center gap-1.5 rounded-md border border-input px-2.5 py-1 text-xs font-medium hover:bg-accent"
|
|
14923
|
+
(click)="copyTree()"
|
|
14924
|
+
>
|
|
14925
|
+
@if (copied()) {
|
|
14926
|
+
<svg
|
|
14927
|
+
class="size-3.5 text-emerald-500"
|
|
14928
|
+
viewBox="0 0 24 24"
|
|
14929
|
+
fill="none"
|
|
14930
|
+
stroke="currentColor"
|
|
14931
|
+
stroke-width="2"
|
|
14932
|
+
stroke-linecap="round"
|
|
14933
|
+
stroke-linejoin="round"
|
|
14934
|
+
aria-hidden="true"
|
|
14935
|
+
>
|
|
14936
|
+
<path d="M20 6 9 17l-5-5" />
|
|
14937
|
+
</svg>
|
|
14938
|
+
{{ copiedText() }}
|
|
14939
|
+
} @else {
|
|
14940
|
+
<svg
|
|
14941
|
+
class="size-3.5"
|
|
14942
|
+
viewBox="0 0 24 24"
|
|
14943
|
+
fill="none"
|
|
14944
|
+
stroke="currentColor"
|
|
14945
|
+
stroke-width="2"
|
|
14946
|
+
stroke-linecap="round"
|
|
14947
|
+
stroke-linejoin="round"
|
|
14948
|
+
aria-hidden="true"
|
|
14949
|
+
>
|
|
14950
|
+
<rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
|
|
14951
|
+
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
|
|
14952
|
+
</svg>
|
|
14953
|
+
{{ copyText() }}
|
|
14954
|
+
}
|
|
14955
|
+
</button>
|
|
14956
|
+
</div>
|
|
14957
|
+
}
|
|
14711
14958
|
<table class="w-full text-sm">
|
|
14712
14959
|
<thead>
|
|
14713
14960
|
<tr class="border-b">
|
|
@@ -14764,7 +15011,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
14764
15011
|
</table>
|
|
14765
15012
|
`,
|
|
14766
15013
|
}]
|
|
14767
|
-
}], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], toggleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleLabel", required: false }] }] } });
|
|
15014
|
+
}], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], toggleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleLabel", required: false }] }], copyable: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyable", required: false }] }], copyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyLabel", required: false }] }], copiedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "copiedLabel", required: false }] }] } });
|
|
14768
15015
|
|
|
14769
15016
|
// HTML is escaped first, then a safe subset of markdown is applied, so user input can't inject markup.
|
|
14770
15017
|
function renderMarkdown(markdown) {
|
|
@@ -16068,7 +16315,7 @@ class BuiContextMenu {
|
|
|
16068
16315
|
this.open.set(false);
|
|
16069
16316
|
}
|
|
16070
16317
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiContextMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16071
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiContextMenu, isStandalone: true, selector: "bui-context-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, host: { attributes: { "data-slot": "context-menu" }, listeners: { "contextmenu": "onContext($event)", "document:click": "open.set(false)", "document:keydown.escape": "open.set(false)" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
16318
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiContextMenu, isStandalone: true, selector: "bui-context-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, host: { attributes: { "data-slot": "context-menu" }, listeners: { "contextmenu": "onContext($event)", "document:click": "open.set(false)", "document:keydown.escape": "open.set(false)", "window:scroll": "open.set(false)" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
|
|
16072
16319
|
<ng-content />
|
|
16073
16320
|
@if (open()) {
|
|
16074
16321
|
<div
|
|
@@ -16181,6 +16428,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
16181
16428
|
'(contextmenu)': 'onContext($event)',
|
|
16182
16429
|
'(document:click)': 'open.set(false)',
|
|
16183
16430
|
'(document:keydown.escape)': 'open.set(false)',
|
|
16431
|
+
// The menu is fixed to viewport coordinates captured at open time; close it on scroll
|
|
16432
|
+
// instead of letting it hang at a now-wrong position.
|
|
16433
|
+
'(window:scroll)': 'open.set(false)',
|
|
16184
16434
|
},
|
|
16185
16435
|
template: `
|
|
16186
16436
|
<ng-content />
|
|
@@ -18325,36 +18575,38 @@ class BuiNavigationMenu {
|
|
|
18325
18575
|
</svg>
|
|
18326
18576
|
</button>
|
|
18327
18577
|
@if (active() === i) {
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
>
|
|
18331
|
-
|
|
18332
|
-
|
|
18333
|
-
|
|
18334
|
-
|
|
18335
|
-
|
|
18336
|
-
|
|
18337
|
-
|
|
18338
|
-
|
|
18339
|
-
|
|
18340
|
-
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
18344
|
-
<ul class="space-y-1">
|
|
18345
|
-
@for (link of item.links; track link.label) {
|
|
18346
|
-
<li>
|
|
18347
|
-
<a [href]="href(link.href)" class="block rounded-md p-2 hover:bg-accent">
|
|
18348
|
-
<span class="text-sm font-medium">{{ link.label }}</span>
|
|
18349
|
-
@if (link.description) {
|
|
18350
|
-
<span class="block text-xs text-muted-foreground">{{
|
|
18351
|
-
link.description
|
|
18352
|
-
}}</span>
|
|
18353
|
-
}
|
|
18354
|
-
</a>
|
|
18355
|
-
</li>
|
|
18578
|
+
<!-- pt-1.5 (not mt-1.5) keeps the gap below the trigger hoverable, so moving the
|
|
18579
|
+
cursor onto the panel doesn't leave the menu and snap it shut. -->
|
|
18580
|
+
<div class="absolute start-0 top-full z-50 w-64 pt-1.5">
|
|
18581
|
+
<div class="rounded-lg border bg-popover p-2 shadow-md">
|
|
18582
|
+
@if (item.featured; as featured) {
|
|
18583
|
+
<a
|
|
18584
|
+
[href]="href(featured.href)"
|
|
18585
|
+
class="mb-1 block rounded-md bg-accent/50 p-3 hover:bg-accent"
|
|
18586
|
+
>
|
|
18587
|
+
<span class="text-sm font-semibold">{{ featured.label }}</span>
|
|
18588
|
+
@if (featured.description) {
|
|
18589
|
+
<span class="mt-0.5 block text-xs text-muted-foreground">{{
|
|
18590
|
+
featured.description
|
|
18591
|
+
}}</span>
|
|
18592
|
+
}
|
|
18593
|
+
</a>
|
|
18356
18594
|
}
|
|
18357
|
-
|
|
18595
|
+
<ul class="space-y-1">
|
|
18596
|
+
@for (link of item.links; track link.label) {
|
|
18597
|
+
<li>
|
|
18598
|
+
<a [href]="href(link.href)" class="block rounded-md p-2 hover:bg-accent">
|
|
18599
|
+
<span class="text-sm font-medium">{{ link.label }}</span>
|
|
18600
|
+
@if (link.description) {
|
|
18601
|
+
<span class="block text-xs text-muted-foreground">{{
|
|
18602
|
+
link.description
|
|
18603
|
+
}}</span>
|
|
18604
|
+
}
|
|
18605
|
+
</a>
|
|
18606
|
+
</li>
|
|
18607
|
+
}
|
|
18608
|
+
</ul>
|
|
18609
|
+
</div>
|
|
18358
18610
|
</div>
|
|
18359
18611
|
}
|
|
18360
18612
|
} @else {
|
|
@@ -18405,36 +18657,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
18405
18657
|
</svg>
|
|
18406
18658
|
</button>
|
|
18407
18659
|
@if (active() === i) {
|
|
18408
|
-
|
|
18409
|
-
|
|
18410
|
-
>
|
|
18411
|
-
|
|
18412
|
-
|
|
18413
|
-
|
|
18414
|
-
|
|
18415
|
-
|
|
18416
|
-
|
|
18417
|
-
|
|
18418
|
-
|
|
18419
|
-
|
|
18420
|
-
|
|
18421
|
-
|
|
18422
|
-
|
|
18423
|
-
|
|
18424
|
-
<ul class="space-y-1">
|
|
18425
|
-
@for (link of item.links; track link.label) {
|
|
18426
|
-
<li>
|
|
18427
|
-
<a [href]="href(link.href)" class="block rounded-md p-2 hover:bg-accent">
|
|
18428
|
-
<span class="text-sm font-medium">{{ link.label }}</span>
|
|
18429
|
-
@if (link.description) {
|
|
18430
|
-
<span class="block text-xs text-muted-foreground">{{
|
|
18431
|
-
link.description
|
|
18432
|
-
}}</span>
|
|
18433
|
-
}
|
|
18434
|
-
</a>
|
|
18435
|
-
</li>
|
|
18660
|
+
<!-- pt-1.5 (not mt-1.5) keeps the gap below the trigger hoverable, so moving the
|
|
18661
|
+
cursor onto the panel doesn't leave the menu and snap it shut. -->
|
|
18662
|
+
<div class="absolute start-0 top-full z-50 w-64 pt-1.5">
|
|
18663
|
+
<div class="rounded-lg border bg-popover p-2 shadow-md">
|
|
18664
|
+
@if (item.featured; as featured) {
|
|
18665
|
+
<a
|
|
18666
|
+
[href]="href(featured.href)"
|
|
18667
|
+
class="mb-1 block rounded-md bg-accent/50 p-3 hover:bg-accent"
|
|
18668
|
+
>
|
|
18669
|
+
<span class="text-sm font-semibold">{{ featured.label }}</span>
|
|
18670
|
+
@if (featured.description) {
|
|
18671
|
+
<span class="mt-0.5 block text-xs text-muted-foreground">{{
|
|
18672
|
+
featured.description
|
|
18673
|
+
}}</span>
|
|
18674
|
+
}
|
|
18675
|
+
</a>
|
|
18436
18676
|
}
|
|
18437
|
-
|
|
18677
|
+
<ul class="space-y-1">
|
|
18678
|
+
@for (link of item.links; track link.label) {
|
|
18679
|
+
<li>
|
|
18680
|
+
<a [href]="href(link.href)" class="block rounded-md p-2 hover:bg-accent">
|
|
18681
|
+
<span class="text-sm font-medium">{{ link.label }}</span>
|
|
18682
|
+
@if (link.description) {
|
|
18683
|
+
<span class="block text-xs text-muted-foreground">{{
|
|
18684
|
+
link.description
|
|
18685
|
+
}}</span>
|
|
18686
|
+
}
|
|
18687
|
+
</a>
|
|
18688
|
+
</li>
|
|
18689
|
+
}
|
|
18690
|
+
</ul>
|
|
18691
|
+
</div>
|
|
18438
18692
|
</div>
|
|
18439
18693
|
}
|
|
18440
18694
|
} @else {
|
|
@@ -19209,9 +19463,16 @@ class BuiRichTextEditor {
|
|
|
19209
19463
|
}
|
|
19210
19464
|
sync() {
|
|
19211
19465
|
const element = this.editor()?.nativeElement;
|
|
19212
|
-
if (element) {
|
|
19213
|
-
|
|
19466
|
+
if (!element) {
|
|
19467
|
+
return;
|
|
19468
|
+
}
|
|
19469
|
+
// Browsers leave residual markup (e.g. `<p><br></p>`) after the user clears
|
|
19470
|
+
// all text, which keeps `:empty` from matching so the placeholder never
|
|
19471
|
+
// reappears. Normalise truly-empty content so the placeholder can show again.
|
|
19472
|
+
if (element.textContent === '' && !element.querySelector('img, hr')) {
|
|
19473
|
+
element.innerHTML = '';
|
|
19214
19474
|
}
|
|
19475
|
+
this.value.set(element.innerHTML);
|
|
19215
19476
|
}
|
|
19216
19477
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiRichTextEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
19217
19478
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiRichTextEditor, isStandalone: true, selector: "bui-rich-text-editor", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, formattingLabel: { classPropertyName: "formattingLabel", publicName: "formattingLabel", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "data-slot": "rich-text-editor" }, properties: { "class": "computedClass()" } }, viewQueries: [{ propertyName: "editor", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
@@ -19240,7 +19501,7 @@ class BuiRichTextEditor {
|
|
|
19240
19501
|
[attr.aria-label]="ariaLabel()"
|
|
19241
19502
|
[attr.data-placeholder]="placeholder()"
|
|
19242
19503
|
contenteditable="true"
|
|
19243
|
-
class="min-h-32 p-3 text-sm text-foreground text-muted-foreground/60
|
|
19504
|
+
class="min-h-32 p-3 text-sm text-foreground outline-none empty:before:text-muted-foreground/60 empty:before:content-[attr(data-placeholder)]"
|
|
19244
19505
|
(input)="sync()"
|
|
19245
19506
|
></div>
|
|
19246
19507
|
`, isInline: true });
|
|
@@ -19276,7 +19537,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
19276
19537
|
[attr.aria-label]="ariaLabel()"
|
|
19277
19538
|
[attr.data-placeholder]="placeholder()"
|
|
19278
19539
|
contenteditable="true"
|
|
19279
|
-
class="min-h-32 p-3 text-sm text-foreground text-muted-foreground/60
|
|
19540
|
+
class="min-h-32 p-3 text-sm text-foreground outline-none empty:before:text-muted-foreground/60 empty:before:content-[attr(data-placeholder)]"
|
|
19280
19541
|
(input)="sync()"
|
|
19281
19542
|
></div>
|
|
19282
19543
|
`,
|
|
@@ -19379,6 +19640,11 @@ class BuiOnboardingTour {
|
|
|
19379
19640
|
prev() {
|
|
19380
19641
|
this.step.set(Math.max(0, this.step() - 1));
|
|
19381
19642
|
}
|
|
19643
|
+
onViewportChange() {
|
|
19644
|
+
if (this.open()) {
|
|
19645
|
+
this.measure();
|
|
19646
|
+
}
|
|
19647
|
+
}
|
|
19382
19648
|
finish() {
|
|
19383
19649
|
this.open.set(false);
|
|
19384
19650
|
this.step.set(0);
|
|
@@ -19395,7 +19661,7 @@ class BuiOnboardingTour {
|
|
|
19395
19661
|
}
|
|
19396
19662
|
}
|
|
19397
19663
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiOnboardingTour, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
19398
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiOnboardingTour, isStandalone: true, selector: "bui-onboarding-tour", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "onboarding-tour" }, listeners: { "document:keydown.escape": "finish()" } }, ngImport: i0, template: `
|
|
19664
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiOnboardingTour, isStandalone: true, selector: "bui-onboarding-tour", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "onboarding-tour" }, listeners: { "document:keydown.escape": "finish()", "window:scroll": "onViewportChange()", "window:resize": "onViewportChange()" } }, ngImport: i0, template: `
|
|
19399
19665
|
@if (open() && current()) {
|
|
19400
19666
|
<div
|
|
19401
19667
|
class="pointer-events-none fixed z-[60] rounded-md ring-2 ring-primary transition-all"
|
|
@@ -19448,7 +19714,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
19448
19714
|
type: Component,
|
|
19449
19715
|
args: [{
|
|
19450
19716
|
selector: 'bui-onboarding-tour',
|
|
19451
|
-
host: {
|
|
19717
|
+
host: {
|
|
19718
|
+
'data-slot': 'onboarding-tour',
|
|
19719
|
+
'(document:keydown.escape)': 'finish()',
|
|
19720
|
+
// The spotlight/card use viewport (fixed) coordinates; re-measure on scroll & resize so the
|
|
19721
|
+
// highlight tracks its target instead of drifting out of alignment.
|
|
19722
|
+
'(window:scroll)': 'onViewportChange()',
|
|
19723
|
+
'(window:resize)': 'onViewportChange()',
|
|
19724
|
+
},
|
|
19452
19725
|
template: `
|
|
19453
19726
|
@if (open() && current()) {
|
|
19454
19727
|
<div
|