@kodaris/krubble-app-components 1.0.13 → 1.0.15

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.
@@ -1403,6 +1403,34 @@
1403
1403
  this.originalXhrOpen = null;
1404
1404
  }
1405
1405
  }
1406
+ /**
1407
+ * Resolves a navigation URL by prepending the base href.
1408
+ *
1409
+ * This method is used for:
1410
+ * 1. Setting href attributes on anchor elements (so Cmd/Ctrl+click opens correct URL in new tab)
1411
+ * 2. Comparing URLs with window.location.pathname in updateActiveNavItem()
1412
+ *
1413
+ * The original item.url is kept intact (without base href) and passed to Angular
1414
+ * via the nav-item-click event. Angular Router expects paths relative to base,
1415
+ * so it handles the base href internally.
1416
+ *
1417
+ * Example with base href "/operations/":
1418
+ * - item.url = "/settings" (used for Angular routing)
1419
+ * - resolveUrl(item) = "/operations/settings" (used for href and URL comparison)
1420
+ */
1421
+ resolveUrl(item) {
1422
+ if (!item.url)
1423
+ return '#';
1424
+ // External URLs - return as-is
1425
+ if (item.external) {
1426
+ return item.url;
1427
+ }
1428
+ // Remove leading slash from url if present, then combine with base
1429
+ const path = item.url.startsWith('/') ? item.url.slice(1) : item.url;
1430
+ const baseHref = document.querySelector('base')?.getAttribute('href') || '/';
1431
+ const base = baseHref.endsWith('/') ? baseHref : (baseHref + '/');
1432
+ return base + path;
1433
+ }
1406
1434
  // =========================================================================
1407
1435
  // Navigation Data
1408
1436
  // =========================================================================
@@ -1478,6 +1506,14 @@
1478
1506
  if (this.navQuery) {
1479
1507
  const query = this.navQuery.toLowerCase();
1480
1508
  const allItems = this.getComputedNav();
1509
+ // If we're getting children of a group, check if parent group name matches query
1510
+ // If so, show all children without filtering
1511
+ if (parentId !== null) {
1512
+ const parentGroup = allItems.find(item => item.id === parentId);
1513
+ if (parentGroup?.label.toLowerCase().includes(query)) {
1514
+ return items; // Show all children when group name matches
1515
+ }
1516
+ }
1481
1517
  items = items.filter(item => {
1482
1518
  if (item.type === 'group') {
1483
1519
  // Show group if its label matches OR if it has matching children
@@ -1536,7 +1572,7 @@
1536
1572
  * Handles click on the nav header (logo/title) to navigate home.
1537
1573
  * Dispatches a nav-item-click event so Angular can intercept and route.
1538
1574
  */
1539
- handleNavHeaderClick(_e) {
1575
+ handleNavHeaderClick() {
1540
1576
  // Clear active state since we're going home
1541
1577
  this.activeNavItemId = null;
1542
1578
  const navEvent = new CustomEvent('nav-item-click', {
@@ -1612,6 +1648,10 @@
1612
1648
  this.toggleNavItem(item.id);
1613
1649
  }
1614
1650
  else {
1651
+ // Allow Ctrl/Cmd+click and middle-click to open in new tab without SPA navigation
1652
+ if (e.ctrlKey || e.metaKey || e.button === 1) {
1653
+ return;
1654
+ }
1615
1655
  // Set active item immediately on click for instant visual feedback
1616
1656
  this.activeNavItemId = item.id;
1617
1657
  const navEvent = new CustomEvent('nav-item-click', {
@@ -1644,7 +1684,8 @@
1644
1684
  let activeItem = null;
1645
1685
  let longestMatch = 0;
1646
1686
  for (const item of allItems) {
1647
- const url = item.url; // We filtered for items with url above
1687
+ // Use resolveUrl because currentPath includes base href
1688
+ const url = this.resolveUrl(item);
1648
1689
  if (currentPath.startsWith(url) && url.length > longestMatch) {
1649
1690
  activeItem = item;
1650
1691
  longestMatch = url.length;
@@ -2219,7 +2260,7 @@
2219
2260
  'nav-item--drop-below': this.navItemDropTargetId === item.id && this.navItemDropPosition === 'below',
2220
2261
  })}
2221
2262
  data-id="${item.id}"
2222
- href=${item.url || '#'}
2263
+ href=${this.resolveUrl(item)}
2223
2264
  target=${item.external ? '_blank' : A}
2224
2265
  @mousedown=${(e) => this.handleNavItemMouseDown(e, item)}
2225
2266
  @click=${(e) => this.handleNavItemClick(e, item)}
@@ -2328,9 +2369,8 @@
2328
2369
  --kr-scaffold-nav-active-bg: #e5e7eb;
2329
2370
  --kr-scaffold-nav-border: rgb(229, 229, 228);
2330
2371
  --kr-scaffold-nav-divider: #e5e7eb;
2331
- --kr-scaffold-nav-search-bg: #f3f4f6;
2332
- --kr-scaffold-nav-search-focus-bg: #ffffff;
2333
- --kr-scaffold-nav-search-focus-border: #d1d5db;
2372
+ --kr-scaffold-nav-search-bg: #ffffff;
2373
+ --kr-scaffold-nav-search-border: #d1d5db;
2334
2374
  }
2335
2375
 
2336
2376
  /* Dark scheme */
@@ -2343,8 +2383,7 @@
2343
2383
  --kr-scaffold-nav-border: transparent;
2344
2384
  --kr-scaffold-nav-divider: rgba(255, 255, 255, 0.06);
2345
2385
  --kr-scaffold-nav-search-bg: rgba(255, 255, 255, 0.15);
2346
- --kr-scaffold-nav-search-focus-bg: rgba(255, 255, 255, 0.2);
2347
- --kr-scaffold-nav-search-focus-border: rgba(255, 255, 255, 0.3);
2386
+ --kr-scaffold-nav-search-border: rgba(255, 255, 255, 0.3);
2348
2387
  }
2349
2388
 
2350
2389
  *,
@@ -2422,15 +2461,10 @@
2422
2461
  padding: 0 12px;
2423
2462
  height: 40px;
2424
2463
  gap: 8px;
2425
- border: 1px solid transparent;
2464
+ border: 1px solid var(--kr-scaffold-nav-search-border);
2426
2465
  transition: all 0.15s ease;
2427
2466
  }
2428
2467
 
2429
- .nav-search__wrapper:focus-within {
2430
- background: var(--kr-scaffold-nav-search-focus-bg);
2431
- border-color: var(--kr-scaffold-nav-search-focus-border);
2432
- }
2433
-
2434
2468
  .nav-search__icon {
2435
2469
  width: 18px;
2436
2470
  height: 18px;
@@ -3539,6 +3573,29 @@
3539
3573
  _handleMenuClick() {
3540
3574
  this.dispatchEvent(new CustomEvent('menu-click', { bubbles: true, composed: true }));
3541
3575
  }
3576
+ /**
3577
+ * Resolves a breadcrumb URL by prepending the base href.
3578
+ *
3579
+ * This method is used for setting href attributes on anchor elements
3580
+ * (so Cmd/Ctrl+click opens correct URL in new tab).
3581
+ *
3582
+ * The original crumb.url is kept intact (without base href) and passed to Angular
3583
+ * via the breadcrumb-click event. Angular Router expects paths relative to base,
3584
+ * so it handles the base href internally.
3585
+ *
3586
+ * Example with base href "/operations/":
3587
+ * - crumb.url = "/settings" (used for Angular routing)
3588
+ * - resolveUrl(crumb) = "/operations/settings" (used for href)
3589
+ */
3590
+ resolveUrl(crumb) {
3591
+ if (!crumb.url)
3592
+ return '#';
3593
+ // Remove leading slash from url if present, then combine with base
3594
+ const path = crumb.url.startsWith('/') ? crumb.url.slice(1) : crumb.url;
3595
+ const baseHref = document.querySelector('base')?.getAttribute('href') || '/';
3596
+ const base = baseHref.endsWith('/') ? baseHref : (baseHref + '/');
3597
+ return base + path;
3598
+ }
3542
3599
  /**
3543
3600
  * Handles click on a breadcrumb link.
3544
3601
  * Dispatches a cancelable event so SPA routers can intercept.
@@ -3549,6 +3606,10 @@
3549
3606
  e.preventDefault();
3550
3607
  return;
3551
3608
  }
3609
+ // Allow Ctrl/Cmd+click and middle-click to open in new tab without SPA navigation
3610
+ if (e.ctrlKey || e.metaKey || e.button === 1) {
3611
+ return;
3612
+ }
3552
3613
  const breadcrumbEvent = new CustomEvent('breadcrumb-click', {
3553
3614
  detail: { breadcrumb: crumb },
3554
3615
  bubbles: true,
@@ -3579,7 +3640,7 @@
3579
3640
  ${index > 0 ? b `<span class="breadcrumb-separator">/</span>` : ''}
3580
3641
  <a
3581
3642
  class=${e$1({ 'breadcrumb': true, 'breadcrumb--current': isCurrent })}
3582
- href=${crumb.url || ''}
3643
+ href=${this.resolveUrl(crumb)}
3583
3644
  @click=${(e) => this._handleBreadcrumbClick(e, crumb, isCurrent)}
3584
3645
  >${crumb.label}</a>
3585
3646
  `;
@@ -3603,6 +3664,7 @@
3603
3664
  align-items: center;
3604
3665
  padding: 0 16px;
3605
3666
  width: 100%;
3667
+ flex-shrink: 0;
3606
3668
  }
3607
3669
 
3608
3670
  .breadcrumbs {