@brickclay-org/ui 0.1.84 → 0.1.85

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.
@@ -4231,9 +4231,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4231
4231
  type: Output
4232
4232
  }] } });
4233
4233
 
4234
+ /**
4235
+ * Shared document/window listeners for `bkTooltip`.
4236
+ *
4237
+ * Every directive instance used to declare its own `document:mousedown`,
4238
+ * `window:scroll` and `window:resize` host listeners. On dense screens (the ticket
4239
+ * documents page renders several hundred tooltip hosts) a single click therefore ran
4240
+ * several hundred handlers and — because host listeners mark their view dirty —
4241
+ * forced a full application change-detection pass, which is what made rapid clicking
4242
+ * lock up the page.
4243
+ *
4244
+ * Only a tooltip that is currently visible has anything to do, so tooltips subscribe
4245
+ * while shown and unsubscribe when hidden. The listeners are attached outside the
4246
+ * Angular zone: they only mutate tooltip styles through `Renderer2`, so no change
4247
+ * detection is required.
4248
+ */
4249
+ class BkTooltipInteractionService {
4250
+ zone;
4251
+ visibleTooltips = new Set();
4252
+ listenersAttached = false;
4253
+ constructor(zone) {
4254
+ this.zone = zone;
4255
+ }
4256
+ /** Called when a tooltip becomes visible. */
4257
+ register(tooltip) {
4258
+ this.attachListeners();
4259
+ this.visibleTooltips.add(tooltip);
4260
+ }
4261
+ /** Called when a tooltip is hidden or destroyed. */
4262
+ unregister(tooltip) {
4263
+ this.visibleTooltips.delete(tooltip);
4264
+ }
4265
+ attachListeners() {
4266
+ if (this.listenersAttached) {
4267
+ return;
4268
+ }
4269
+ this.listenersAttached = true;
4270
+ this.zone.runOutsideAngular(() => {
4271
+ const hideAll = () => {
4272
+ this.forEachVisible((tooltip) => tooltip.hideOnGlobalInteraction());
4273
+ };
4274
+ document.addEventListener('mousedown', hideAll);
4275
+ document.addEventListener('touchstart', hideAll);
4276
+ window.addEventListener('scroll', () => {
4277
+ this.forEachVisible((tooltip) => tooltip.repositionOnViewportChange());
4278
+ });
4279
+ window.addEventListener('resize', () => {
4280
+ this.forEachVisible((tooltip) => tooltip.repositionOnViewportChange());
4281
+ });
4282
+ });
4283
+ }
4284
+ forEachVisible(action) {
4285
+ if (this.visibleTooltips.size === 0) {
4286
+ return;
4287
+ }
4288
+ // Copy: hiding a tooltip unregisters it while iterating.
4289
+ for (const tooltip of Array.from(this.visibleTooltips)) {
4290
+ action(tooltip);
4291
+ }
4292
+ }
4293
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTooltipInteractionService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
4294
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTooltipInteractionService, providedIn: 'root' });
4295
+ }
4296
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTooltipInteractionService, decorators: [{
4297
+ type: Injectable,
4298
+ args: [{ providedIn: 'root' }]
4299
+ }], ctorParameters: () => [{ type: i0.NgZone }] });
4300
+
4234
4301
  class BKTooltipDirective {
4235
4302
  el;
4236
4303
  renderer;
4304
+ tooltipInteraction;
4237
4305
  tooltipContent = '';
4238
4306
  tooltipPosition = 'right';
4239
4307
  scrollable = false;
@@ -4245,9 +4313,11 @@ class BKTooltipDirective {
4245
4313
  isHoveringTooltip = false;
4246
4314
  hideTimeout = null;
4247
4315
  tooltipListeners = [];
4248
- constructor(el, renderer) {
4316
+ isRegisteredWithInteractionService = false;
4317
+ constructor(el, renderer, tooltipInteraction) {
4249
4318
  this.el = el;
4250
4319
  this.renderer = renderer;
4320
+ this.tooltipInteraction = tooltipInteraction;
4251
4321
  }
4252
4322
  ngOnInit() {
4253
4323
  this.createTooltip();
@@ -4262,6 +4332,7 @@ class BKTooltipDirective {
4262
4332
  clearTimeout(this.hideTimeout);
4263
4333
  this.hideTimeout = null;
4264
4334
  }
4335
+ this.unregisterFromInteractionService();
4265
4336
  this.cleanupTooltipListeners();
4266
4337
  this.removeTooltip();
4267
4338
  }
@@ -4314,6 +4385,7 @@ class BKTooltipDirective {
4314
4385
  opacity: '1',
4315
4386
  });
4316
4387
  this.renderer.setStyle(document.body, 'overflow-x', 'hidden'); // ✅ temporarily lock horizontal scroll
4388
+ this.registerWithInteractionService();
4317
4389
  }
4318
4390
  }
4319
4391
  onMouseLeave() {
@@ -4336,24 +4408,34 @@ class BKTooltipDirective {
4336
4408
  // this.renderer.removeStyle(document.body, 'overflow-x');
4337
4409
  // }
4338
4410
  // }
4339
- // Hide tooltip the instant *any* mousedown happens, not just on this host:
4340
- // otherwise a tooltip shown by hovering one element (e.g. a "+N" badge)
4341
- // can still be mid-fade — mouseleave's hide is debounced 100ms and the
4342
- // fade itself takes 300ms — when a click elsewhere opens something else
4343
- // (a dropdown panel, another tooltip's host), so the two stack visibly.
4344
- // Also covers CDK drag-drop, which steals the element before mouseleave fires.
4345
- onInteract() {
4411
+ /** @see BkTooltipInteractionService shared document/window listeners */
4412
+ hideOnGlobalInteraction() {
4346
4413
  if (this.hideTimeout) {
4347
4414
  clearTimeout(this.hideTimeout);
4348
4415
  this.hideTimeout = null;
4349
4416
  }
4350
4417
  this.hideTooltipInstant();
4351
4418
  }
4352
- onWindowChange() {
4419
+ /** @see BkTooltipInteractionService — shared document/window listeners */
4420
+ repositionOnViewportChange() {
4353
4421
  if (this.tooltipElement?.style.visibility === 'visible') {
4354
4422
  this.setTooltipPosition();
4355
4423
  }
4356
4424
  }
4425
+ registerWithInteractionService() {
4426
+ if (this.isRegisteredWithInteractionService) {
4427
+ return;
4428
+ }
4429
+ this.tooltipInteraction.register(this);
4430
+ this.isRegisteredWithInteractionService = true;
4431
+ }
4432
+ unregisterFromInteractionService() {
4433
+ if (!this.isRegisteredWithInteractionService) {
4434
+ return;
4435
+ }
4436
+ this.tooltipInteraction.unregister(this);
4437
+ this.isRegisteredWithInteractionService = false;
4438
+ }
4357
4439
  isTooltipContentEmpty() {
4358
4440
  if (typeof this.tooltipContent === 'string') {
4359
4441
  return !this.tooltipContent.trim();
@@ -4385,6 +4467,7 @@ class BKTooltipDirective {
4385
4467
  this.renderer.removeStyle(document.body, 'overflow-x'); // ✅ restore scroll when tooltip hides
4386
4468
  }
4387
4469
  this.isHoveringTooltip = false;
4470
+ this.unregisterFromInteractionService();
4388
4471
  }
4389
4472
  setupTooltipHoverListeners() {
4390
4473
  if (!this.tooltipElement)
@@ -4405,6 +4488,7 @@ class BKTooltipDirective {
4405
4488
  visibility: 'visible',
4406
4489
  opacity: '1',
4407
4490
  });
4491
+ this.registerWithInteractionService();
4408
4492
  }
4409
4493
  });
4410
4494
  // Add mouseleave listener to tooltip
@@ -4465,9 +4549,7 @@ class BKTooltipDirective {
4465
4549
  position: 'fixed',
4466
4550
  visibility: 'hidden',
4467
4551
  opacity: '0',
4468
- // Tooltips can originate inside popovers/dropdowns (z-index 10000).
4469
- // Keep this transient explanatory layer above its owning overlay.
4470
- zIndex: '11000',
4552
+ zIndex: '9999',
4471
4553
  transition: 'opacity 0.3s ease, visibility 0.3s ease',
4472
4554
  maxWidth: '300px',
4473
4555
  wordBreak: 'normal', // ← only break at spaces
@@ -4690,8 +4772,8 @@ class BKTooltipDirective {
4690
4772
  this.renderer.setStyle(el, prop, value);
4691
4773
  });
4692
4774
  }
4693
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BKTooltipDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
4694
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BKTooltipDirective, isStandalone: true, selector: "[bkTooltip]", inputs: { tooltipContent: ["bkTooltip", "tooltipContent"], tooltipPosition: ["bkTooltipPosition", "tooltipPosition"], scrollable: ["bkTooltipScrollable", "scrollable"], maxHeight: ["bkTooltipMaxHeight", "maxHeight"], tooltipSize: ["bkTooltipSize", "tooltipSize"], autoHeight: ["bkTooltipAutoHeight", "autoHeight"] }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "document:mousedown": "onInteract()", "touchstart": "onInteract()", "window:scroll": "onWindowChange()", "window:resize": "onWindowChange()" } }, usesOnChanges: true, ngImport: i0 });
4775
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BKTooltipDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: BkTooltipInteractionService }], target: i0.ɵɵFactoryTarget.Directive });
4776
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BKTooltipDirective, isStandalone: true, selector: "[bkTooltip]", inputs: { tooltipContent: ["bkTooltip", "tooltipContent"], tooltipPosition: ["bkTooltipPosition", "tooltipPosition"], scrollable: ["bkTooltipScrollable", "scrollable"], maxHeight: ["bkTooltipMaxHeight", "maxHeight"], tooltipSize: ["bkTooltipSize", "tooltipSize"], autoHeight: ["bkTooltipAutoHeight", "autoHeight"] }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, usesOnChanges: true, ngImport: i0 });
4695
4777
  }
4696
4778
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BKTooltipDirective, decorators: [{
4697
4779
  type: Directive,
@@ -4699,7 +4781,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4699
4781
  selector: '[bkTooltip]',
4700
4782
  standalone: true,
4701
4783
  }]
4702
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { tooltipContent: [{
4784
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: BkTooltipInteractionService }], propDecorators: { tooltipContent: [{
4703
4785
  type: Input,
4704
4786
  args: ['bkTooltip']
4705
4787
  }], tooltipPosition: [{
@@ -4723,18 +4805,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4723
4805
  }], onMouseLeave: [{
4724
4806
  type: HostListener,
4725
4807
  args: ['mouseleave']
4726
- }], onInteract: [{
4727
- type: HostListener,
4728
- args: ['document:mousedown']
4729
- }, {
4730
- type: HostListener,
4731
- args: ['touchstart']
4732
- }], onWindowChange: [{
4733
- type: HostListener,
4734
- args: ['window:scroll']
4735
- }, {
4736
- type: HostListener,
4737
- args: ['window:resize']
4738
4808
  }] } });
4739
4809
 
4740
4810
  class BkGrid {
@@ -12770,5 +12840,5 @@ const BK_TABLE = [
12770
12840
  * Generated bundle index. Do not edit.
12771
12841
  */
12772
12842
 
12773
- export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, NEUTRAL_APPEARANCE, POPOVER_PLACEMENTS, computePopoverPosition, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
12843
+ export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTooltipInteractionService, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, NEUTRAL_APPEARANCE, POPOVER_PLACEMENTS, computePopoverPosition, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
12774
12844
  //# sourceMappingURL=brickclay-org-ui.mjs.map