@kodaris/krubble-app-components 1.0.13 → 1.0.14

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.
@@ -1400,6 +1400,34 @@ let KRScaffold = class KRScaffold extends i$1 {
1400
1400
  this.originalXhrOpen = null;
1401
1401
  }
1402
1402
  }
1403
+ /**
1404
+ * Resolves a navigation URL by prepending the base href.
1405
+ *
1406
+ * This method is used for:
1407
+ * 1. Setting href attributes on anchor elements (so Cmd/Ctrl+click opens correct URL in new tab)
1408
+ * 2. Comparing URLs with window.location.pathname in updateActiveNavItem()
1409
+ *
1410
+ * The original item.url is kept intact (without base href) and passed to Angular
1411
+ * via the nav-item-click event. Angular Router expects paths relative to base,
1412
+ * so it handles the base href internally.
1413
+ *
1414
+ * Example with base href "/operations/":
1415
+ * - item.url = "/settings" (used for Angular routing)
1416
+ * - resolveUrl(item) = "/operations/settings" (used for href and URL comparison)
1417
+ */
1418
+ resolveUrl(item) {
1419
+ if (!item.url)
1420
+ return '#';
1421
+ // External URLs - return as-is
1422
+ if (item.external) {
1423
+ return item.url;
1424
+ }
1425
+ // Remove leading slash from url if present, then combine with base
1426
+ const path = item.url.startsWith('/') ? item.url.slice(1) : item.url;
1427
+ const baseHref = document.querySelector('base')?.getAttribute('href') || '/';
1428
+ const base = baseHref.endsWith('/') ? baseHref : (baseHref + '/');
1429
+ return base + path;
1430
+ }
1403
1431
  // =========================================================================
1404
1432
  // Navigation Data
1405
1433
  // =========================================================================
@@ -1533,7 +1561,7 @@ let KRScaffold = class KRScaffold extends i$1 {
1533
1561
  * Handles click on the nav header (logo/title) to navigate home.
1534
1562
  * Dispatches a nav-item-click event so Angular can intercept and route.
1535
1563
  */
1536
- handleNavHeaderClick(_e) {
1564
+ handleNavHeaderClick() {
1537
1565
  // Clear active state since we're going home
1538
1566
  this.activeNavItemId = null;
1539
1567
  const navEvent = new CustomEvent('nav-item-click', {
@@ -1609,6 +1637,10 @@ let KRScaffold = class KRScaffold extends i$1 {
1609
1637
  this.toggleNavItem(item.id);
1610
1638
  }
1611
1639
  else {
1640
+ // Allow Ctrl/Cmd+click and middle-click to open in new tab without SPA navigation
1641
+ if (e.ctrlKey || e.metaKey || e.button === 1) {
1642
+ return;
1643
+ }
1612
1644
  // Set active item immediately on click for instant visual feedback
1613
1645
  this.activeNavItemId = item.id;
1614
1646
  const navEvent = new CustomEvent('nav-item-click', {
@@ -1641,7 +1673,8 @@ let KRScaffold = class KRScaffold extends i$1 {
1641
1673
  let activeItem = null;
1642
1674
  let longestMatch = 0;
1643
1675
  for (const item of allItems) {
1644
- const url = item.url; // We filtered for items with url above
1676
+ // Use resolveUrl because currentPath includes base href
1677
+ const url = this.resolveUrl(item);
1645
1678
  if (currentPath.startsWith(url) && url.length > longestMatch) {
1646
1679
  activeItem = item;
1647
1680
  longestMatch = url.length;
@@ -2216,7 +2249,7 @@ let KRScaffold = class KRScaffold extends i$1 {
2216
2249
  'nav-item--drop-below': this.navItemDropTargetId === item.id && this.navItemDropPosition === 'below',
2217
2250
  })}
2218
2251
  data-id="${item.id}"
2219
- href=${item.url || '#'}
2252
+ href=${this.resolveUrl(item)}
2220
2253
  target=${item.external ? '_blank' : A}
2221
2254
  @mousedown=${(e) => this.handleNavItemMouseDown(e, item)}
2222
2255
  @click=${(e) => this.handleNavItemClick(e, item)}
@@ -2325,9 +2358,8 @@ KRScaffold.styles = i$4 `
2325
2358
  --kr-scaffold-nav-active-bg: #e5e7eb;
2326
2359
  --kr-scaffold-nav-border: rgb(229, 229, 228);
2327
2360
  --kr-scaffold-nav-divider: #e5e7eb;
2328
- --kr-scaffold-nav-search-bg: #f3f4f6;
2329
- --kr-scaffold-nav-search-focus-bg: #ffffff;
2330
- --kr-scaffold-nav-search-focus-border: #d1d5db;
2361
+ --kr-scaffold-nav-search-bg: #ffffff;
2362
+ --kr-scaffold-nav-search-border: #d1d5db;
2331
2363
  }
2332
2364
 
2333
2365
  /* Dark scheme */
@@ -2340,8 +2372,7 @@ KRScaffold.styles = i$4 `
2340
2372
  --kr-scaffold-nav-border: transparent;
2341
2373
  --kr-scaffold-nav-divider: rgba(255, 255, 255, 0.06);
2342
2374
  --kr-scaffold-nav-search-bg: rgba(255, 255, 255, 0.15);
2343
- --kr-scaffold-nav-search-focus-bg: rgba(255, 255, 255, 0.2);
2344
- --kr-scaffold-nav-search-focus-border: rgba(255, 255, 255, 0.3);
2375
+ --kr-scaffold-nav-search-border: rgba(255, 255, 255, 0.3);
2345
2376
  }
2346
2377
 
2347
2378
  *,
@@ -2419,15 +2450,10 @@ KRScaffold.styles = i$4 `
2419
2450
  padding: 0 12px;
2420
2451
  height: 40px;
2421
2452
  gap: 8px;
2422
- border: 1px solid transparent;
2453
+ border: 1px solid var(--kr-scaffold-nav-search-border);
2423
2454
  transition: all 0.15s ease;
2424
2455
  }
2425
2456
 
2426
- .nav-search__wrapper:focus-within {
2427
- background: var(--kr-scaffold-nav-search-focus-bg);
2428
- border-color: var(--kr-scaffold-nav-search-focus-border);
2429
- }
2430
-
2431
2457
  .nav-search__icon {
2432
2458
  width: 18px;
2433
2459
  height: 18px;
@@ -3536,6 +3562,29 @@ let KRSubbar = class KRSubbar extends i$1 {
3536
3562
  _handleMenuClick() {
3537
3563
  this.dispatchEvent(new CustomEvent('menu-click', { bubbles: true, composed: true }));
3538
3564
  }
3565
+ /**
3566
+ * Resolves a breadcrumb URL by prepending the base href.
3567
+ *
3568
+ * This method is used for setting href attributes on anchor elements
3569
+ * (so Cmd/Ctrl+click opens correct URL in new tab).
3570
+ *
3571
+ * The original crumb.url is kept intact (without base href) and passed to Angular
3572
+ * via the breadcrumb-click event. Angular Router expects paths relative to base,
3573
+ * so it handles the base href internally.
3574
+ *
3575
+ * Example with base href "/operations/":
3576
+ * - crumb.url = "/settings" (used for Angular routing)
3577
+ * - resolveUrl(crumb) = "/operations/settings" (used for href)
3578
+ */
3579
+ resolveUrl(crumb) {
3580
+ if (!crumb.url)
3581
+ return '#';
3582
+ // Remove leading slash from url if present, then combine with base
3583
+ const path = crumb.url.startsWith('/') ? crumb.url.slice(1) : crumb.url;
3584
+ const baseHref = document.querySelector('base')?.getAttribute('href') || '/';
3585
+ const base = baseHref.endsWith('/') ? baseHref : (baseHref + '/');
3586
+ return base + path;
3587
+ }
3539
3588
  /**
3540
3589
  * Handles click on a breadcrumb link.
3541
3590
  * Dispatches a cancelable event so SPA routers can intercept.
@@ -3546,6 +3595,10 @@ let KRSubbar = class KRSubbar extends i$1 {
3546
3595
  e.preventDefault();
3547
3596
  return;
3548
3597
  }
3598
+ // Allow Ctrl/Cmd+click and middle-click to open in new tab without SPA navigation
3599
+ if (e.ctrlKey || e.metaKey || e.button === 1) {
3600
+ return;
3601
+ }
3549
3602
  const breadcrumbEvent = new CustomEvent('breadcrumb-click', {
3550
3603
  detail: { breadcrumb: crumb },
3551
3604
  bubbles: true,
@@ -3576,7 +3629,7 @@ let KRSubbar = class KRSubbar extends i$1 {
3576
3629
  ${index > 0 ? b `<span class="breadcrumb-separator">/</span>` : ''}
3577
3630
  <a
3578
3631
  class=${e$1({ 'breadcrumb': true, 'breadcrumb--current': isCurrent })}
3579
- href=${crumb.url || ''}
3632
+ href=${this.resolveUrl(crumb)}
3580
3633
  @click=${(e) => this._handleBreadcrumbClick(e, crumb, isCurrent)}
3581
3634
  >${crumb.label}</a>
3582
3635
  `;
@@ -3600,6 +3653,7 @@ KRSubbar.styles = i$4 `
3600
3653
  align-items: center;
3601
3654
  padding: 0 16px;
3602
3655
  width: 100%;
3656
+ flex-shrink: 0;
3603
3657
  }
3604
3658
 
3605
3659
  .breadcrumbs {