@brickclay-org/ui 0.1.71 → 0.1.73

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/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { OnInit, OnDestroy, OnChanges, EventEmitter, ElementRef, SimpleChanges, AfterViewInit, QueryList, ComponentRef, Type, InjectionToken, Renderer2, ApplicationRef, EnvironmentInjector, ChangeDetectorRef } from '@angular/core';
2
+ import { OnInit, OnDestroy, OnChanges, EventEmitter, ElementRef, Renderer2, SimpleChanges, AfterViewInit, QueryList, ComponentRef, Type, InjectionToken, ApplicationRef, EnvironmentInjector, ChangeDetectorRef } from '@angular/core';
3
3
  import { ControlValueAccessor, Validator, AbstractControl, ValidationErrors, NgControl, NgModel } from '@angular/forms';
4
4
  import * as rxjs from 'rxjs';
5
5
  import { Observable } from 'rxjs';
@@ -76,6 +76,7 @@ declare class CalendarSelection {
76
76
  }
77
77
  declare class BkCustomCalendar implements OnInit, OnDestroy, OnChanges, ControlValueAccessor, Validator {
78
78
  private calendarManager;
79
+ private renderer;
79
80
  enableTimepicker: boolean;
80
81
  autoApply: boolean;
81
82
  closeOnAutoApply: boolean;
@@ -205,7 +206,25 @@ declare class BkCustomCalendar implements OnInit, OnDestroy, OnChanges, ControlV
205
206
  private unregisterFn?;
206
207
  private closeAllSubscription?;
207
208
  private closeFn?;
208
- constructor(calendarManager: BkCalendarManagerService);
209
+ constructor(calendarManager: BkCalendarManagerService, renderer: Renderer2);
210
+ /**
211
+ * appendToBody popup relocation.
212
+ *
213
+ * `appendToBody` uses `position: fixed`, which only anchors to the viewport when NO ancestor
214
+ * establishes a containing block (transform / filter / perspective / will-change / contain /
215
+ * backdrop-filter). Consumers frequently place the calendar inside such an ancestor (an animated
216
+ * panel, a CSS-transformed modal, etc.), which silently re-anchors the fixed popup and pushes it
217
+ * off-position. To be robust everywhere we physically move the popup node to <body> while it is
218
+ * open, then move it back before Angular's *ngIf tears it down. Angular keeps managing the node by
219
+ * reference after the move, so its event bindings, change detection, and emulated-encapsulation
220
+ * styles all continue to work.
221
+ */
222
+ private popupMovedToBody;
223
+ private popupOriginalParent;
224
+ private popupOriginalNextSibling;
225
+ private movePopupToBody;
226
+ /** Return the popup to its original DOM slot so *ngIf can destroy it cleanly (safe to call twice). */
227
+ private restorePopupFromBody;
209
228
  /** Weekday headers; falls back to Mon–Sun if the input is not length 7. */
210
229
  get resolvedWeekDayLabels(): string[];
211
230
  /** When dual range mode, Apply is blocked until both endpoints exist. */
@@ -456,6 +475,7 @@ declare class BkScheduledDatePicker implements OnInit {
456
475
  }
457
476
 
458
477
  declare class BkTimePicker implements OnInit, OnChanges, OnDestroy, AfterViewInit, ControlValueAccessor {
478
+ private renderer;
459
479
  required: boolean;
460
480
  /** @deprecated Prefer [(ngModel)] */
461
481
  value: string | null;
@@ -516,6 +536,21 @@ declare class BkTimePicker implements OnInit, OnChanges, OnDestroy, AfterViewIni
516
536
  readonly calenderIcon: "assets/icons/custom-calender.svg";
517
537
  readonly timerIcon: "assets/icons/timer.svg";
518
538
  };
539
+ constructor(renderer: Renderer2);
540
+ /**
541
+ * `appendToBody` anchors the dropdown with `position: fixed`, which only tracks the viewport when
542
+ * NO ancestor establishes a containing block (transform / filter / perspective / will-change /
543
+ * contain / backdrop-filter). Inside such an ancestor the fixed coordinates resolve against that
544
+ * ancestor instead and the dropdown drifts off-position. To be robust we physically move the panel
545
+ * to <body> while open (Angular keeps managing it by reference) and move it back before *ngIf
546
+ * tears it down. The panel carries a `tp-compact` self-class so its `default`-variation sizing —
547
+ * otherwise scoped under the `.time-input-group.default` ancestor it just left — still applies.
548
+ */
549
+ private dropdownMovedToBody;
550
+ private dropdownOriginalParent;
551
+ private moveDropdownToBody;
552
+ /** Return the dropdown to its original slot so *ngIf can destroy it cleanly (safe to call twice). */
553
+ private restoreDropdownFromBody;
519
554
  writeValue(value: string | null): void;
520
555
  registerOnChange(fn: (value: string | null) => void): void;
521
556
  registerOnTouched(fn: () => void): void;
@@ -1235,6 +1270,18 @@ interface TabItem {
1235
1270
  iconTooltip?: string | string[];
1236
1271
  iconTooltipDirection?: 'left' | 'right' | 'top' | 'bottom';
1237
1272
  error?: boolean;
1273
+ /**
1274
+ * When the tab is in an error state, render an error icon (on the side given
1275
+ * by `direction`) with `iconTooltip` shown on hover of the icon.
1276
+ * When false/omitted, no error icon is drawn and `iconTooltip` falls back to
1277
+ * the tab button itself. Works for both variants and orientations.
1278
+ */
1279
+ showErrorIcon?: boolean;
1280
+ /**
1281
+ * Optional custom error icon URL. If omitted while `showErrorIcon` is true,
1282
+ * the component's default error icon is used.
1283
+ */
1284
+ errorIcon?: string;
1238
1285
  }
1239
1286
  declare class BkTabs {
1240
1287
  list: TabItem[];
@@ -1243,16 +1290,26 @@ declare class BkTabs {
1243
1290
  orientation: TabsOrientation;
1244
1291
  variant: TabsVariant;
1245
1292
  colors: TabsColors;
1293
+ /**
1294
+ * When true, if the currently active tab is in an error state, navigation to
1295
+ * the other tabs is blocked (they render disabled) until the error clears.
1296
+ * Optional — defaults to false, so navigation stays free unless opted in.
1297
+ */
1298
+ lockNavigationOnError: boolean;
1299
+ /** Fallback error icon used when a tab has `showErrorIcon` but no `errorIcon`. */
1300
+ private readonly defaultErrorIcon;
1246
1301
  get isVertical(): boolean;
1247
1302
  get isSegmented(): boolean;
1248
1303
  get wrapperClass(): string;
1249
1304
  segmentedTabClass(tab: TabItem): string;
1250
1305
  change: EventEmitter<TabItem>;
1306
+ get activeTabHasError(): boolean;
1307
+ isLocked(tab: TabItem): boolean;
1251
1308
  setActiveTab(tab: TabItem): void;
1252
1309
  isActive(tabId: string): boolean;
1253
1310
  getTabIcon(tab: TabItem): string | undefined;
1254
1311
  static ɵfac: i0.ɵɵFactoryDeclaration<BkTabs, never>;
1255
- static ɵcmp: i0.ɵɵComponentDeclaration<BkTabs, "bk-tabs", never, { "list": { "alias": "list"; "required": false; }; "activeTabId": { "alias": "activeTabId"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "orientation": { "alias": "orientation"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "colors": { "alias": "colors"; "required": false; }; }, { "change": "change"; }, never, never, true, never>;
1312
+ static ɵcmp: i0.ɵɵComponentDeclaration<BkTabs, "bk-tabs", never, { "list": { "alias": "list"; "required": false; }; "activeTabId": { "alias": "activeTabId"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "orientation": { "alias": "orientation"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "colors": { "alias": "colors"; "required": false; }; "lockNavigationOnError": { "alias": "lockNavigationOnError"; "required": false; }; }, { "change": "change"; }, never, never, true, never>;
1256
1313
  }
1257
1314
 
1258
1315
  /**
@@ -2515,5 +2572,86 @@ declare class BkDropdown {
2515
2572
  static ɵcmp: i0.ɵɵComponentDeclaration<BkDropdown, "bk-dropdown", never, { "label": { "alias": "label"; "required": false; }; "items": { "alias": "items"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "size": { "alias": "size"; "required": false; }; "trigger": { "alias": "trigger"; "required": false; }; "placement": { "alias": "placement"; "required": false; }; "arrow": { "alias": "arrow"; "required": false; }; "splitButton": { "alias": "splitButton"; "required": false; }; "selectedId": { "alias": "selectedId"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "iconSrc": { "alias": "iconSrc"; "required": false; }; "customClass": { "alias": "customClass"; "required": false; }; }, { "select": "select"; "openChange": "openChange"; "buttonClick": "buttonClick"; }, never, never, true, never>;
2516
2573
  }
2517
2574
 
2518
- export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BkAvatar, BkAvatarUploader, BkBadge, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkPagination, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, getDialogBackdropAnimation, getDialogPanelAnimation };
2519
- export type { AvatarFallback, AvatarSize, AvatarVariant, BadgeColor, BadgeSize, BadgeVariant, BkAnimationKeyframes, BkAvatarFallback, BkAvatarSize, BkDialogAnimation, BkDialogConfig, BkDialogPosition, BkInputAutoCapitalize, BkInputAutoComplete, BkInputMode, BkInputType, BkLoaderVariant, BkPageSize, BkTextAreaAutoCapitalize, BkTextAreaAutoComplete, BkTextAreaInputMode, ButtonSize, ButtonVariant, CalendarRange, CountryOption, CustomRangesConfig, DotPosition, DotStatus, DropdownItem, DropdownPlacement, DropdownSize, DropdownTrigger, DropdownVariant, FileState, GroupItem, GroupMode, HierarchicalNode, IconButtonSize, IconButtonVariant, IconOrientation, PillColor, PillSize, PillVariant, ScheduledDateSelection, SortDirection, SpinnerSize, TabIconDirection, TabItem, TableAction, TableBadge, TableColumn, TableIcon, TabsColors, TabsOrientation, TabsVariant, TimeConfiguration, ToastConfig, ToastMessage, ToastMethodOptions, ToastPosition, ToastSeverity };
2575
+ type MenuOrientation = 'horizontal' | 'vertical';
2576
+ type MenuSubmenuMode = 'inline' | 'popup';
2577
+ interface MenuItem {
2578
+ /** Unique id — matched against `activeItemId`. */
2579
+ id: string;
2580
+ /** Visible menu text. */
2581
+ label: string;
2582
+ /** Optional icon URL (tinted to the theme unless `tintIcons` is false). */
2583
+ icon?: string;
2584
+ /** Alt text for the icon; defaults to `label`. */
2585
+ iconAlt?: string;
2586
+ /** Disables just this item (and blocks opening its submenu). */
2587
+ disabled?: boolean;
2588
+ /** Nested items — presence of children turns this into an expandable node. */
2589
+ children?: MenuItem[];
2590
+ }
2591
+ /**
2592
+ * A simple, responsive navigation menu. Styled to match the default `bk-tabs`
2593
+ * theme (dark active pill, light hover).
2594
+ *
2595
+ * - Orientation: `vertical` (stacked) / `horizontal` (menubar row).
2596
+ * - Items with `children` are expandable, shown with a chevron that rotates
2597
+ * open/closed.
2598
+ * - Submenus render inline (accordion) or as pop-ups. Pop-ups adapt to the
2599
+ * orientation: they drop *below* a horizontal top-level item and fly out to
2600
+ * the *right* for vertical menus / deeper levels.
2601
+ */
2602
+ declare class BkMenu {
2603
+ private readonly host;
2604
+ items: MenuItem[];
2605
+ orientation: MenuOrientation;
2606
+ submenuMode: MenuSubmenuMode;
2607
+ /**
2608
+ * Keep only one submenu open per level: opening a parent collapses its
2609
+ * siblings (and their descendants) so the menu stays compact. Pop-up mode
2610
+ * always behaves this way; this input adds it to inline (accordion) mode.
2611
+ */
2612
+ singleOpen: boolean;
2613
+ /** Id of the currently selected leaf item. Two-way bindable. */
2614
+ activeItemId: string;
2615
+ /** Tint item icons: dark by default, white on the active (dark) row. */
2616
+ tintIcons: boolean;
2617
+ /**
2618
+ * Optional max height for the menu (e.g. '320px', '60vh', or a number of px).
2619
+ * When set, the item list scrolls vertically once it exceeds this height.
2620
+ * Pop-up fly-outs are positioned `fixed`, so they still escape the scroll box.
2621
+ */
2622
+ maxHeight: string | number | null;
2623
+ activeItemIdChange: EventEmitter<string>;
2624
+ itemClick: EventEmitter<MenuItem>;
2625
+ /** Ids of currently expanded/opened parent nodes. */
2626
+ private readonly openIds;
2627
+ /** Viewport coordinates for each open fixed-position fly-out, keyed by id. */
2628
+ readonly popupPos: Map<string, {
2629
+ top: number;
2630
+ left: number;
2631
+ }>;
2632
+ constructor(host: ElementRef<HTMLElement>);
2633
+ get isVertical(): boolean;
2634
+ get isPopup(): boolean;
2635
+ get maxHeightStyle(): string | null;
2636
+ popupTop(item: MenuItem): number | null;
2637
+ popupLeft(item: MenuItem): number | null;
2638
+ hasChildren(item: MenuItem): boolean;
2639
+ isOpen(item: MenuItem): boolean;
2640
+ isActive(item: MenuItem): boolean;
2641
+ isActiveAncestor(item: MenuItem): boolean;
2642
+ isHighlighted(item: MenuItem): boolean;
2643
+ inlineIndent(level: number): number | null;
2644
+ onItemClick(item: MenuItem, siblings: MenuItem[], event: Event): void;
2645
+ onItemEnter(item: MenuItem, siblings: MenuItem[], event: MouseEvent, level: number): void;
2646
+ private computePopupPos;
2647
+ onItemLeave(item: MenuItem): void;
2648
+ private toggle;
2649
+ private closeBranch;
2650
+ onDocumentClick(event: MouseEvent): void;
2651
+ onViewportChange(): void;
2652
+ static ɵfac: i0.ɵɵFactoryDeclaration<BkMenu, never>;
2653
+ static ɵcmp: i0.ɵɵComponentDeclaration<BkMenu, "bk-menu", never, { "items": { "alias": "items"; "required": false; }; "orientation": { "alias": "orientation"; "required": false; }; "submenuMode": { "alias": "submenuMode"; "required": false; }; "singleOpen": { "alias": "singleOpen"; "required": false; }; "activeItemId": { "alias": "activeItemId"; "required": false; }; "tintIcons": { "alias": "tintIcons"; "required": false; }; "maxHeight": { "alias": "maxHeight"; "required": false; }; }, { "activeItemIdChange": "activeItemIdChange"; "itemClick": "itemClick"; }, never, never, true, never>;
2654
+ }
2655
+
2656
+ export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BkAvatar, BkAvatarUploader, BkBadge, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, getDialogBackdropAnimation, getDialogPanelAnimation };
2657
+ export type { AvatarFallback, AvatarSize, AvatarVariant, BadgeColor, BadgeSize, BadgeVariant, BkAnimationKeyframes, BkAvatarFallback, BkAvatarSize, BkDialogAnimation, BkDialogConfig, BkDialogPosition, BkInputAutoCapitalize, BkInputAutoComplete, BkInputMode, BkInputType, BkLoaderVariant, BkPageSize, BkTextAreaAutoCapitalize, BkTextAreaAutoComplete, BkTextAreaInputMode, ButtonSize, ButtonVariant, CalendarRange, CountryOption, CustomRangesConfig, DotPosition, DotStatus, DropdownItem, DropdownPlacement, DropdownSize, DropdownTrigger, DropdownVariant, FileState, GroupItem, GroupMode, HierarchicalNode, IconButtonSize, IconButtonVariant, IconOrientation, MenuItem, MenuOrientation, MenuSubmenuMode, PillColor, PillSize, PillVariant, ScheduledDateSelection, SortDirection, SpinnerSize, TabIconDirection, TabItem, TableAction, TableBadge, TableColumn, TableIcon, TabsColors, TabsOrientation, TabsVariant, TimeConfiguration, ToastConfig, ToastMessage, ToastMethodOptions, ToastPosition, ToastSeverity };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brickclay-org/ui",
3
- "version": "0.1.71",
3
+ "version": "0.1.73",
4
4
  "schematics": "./schematics/collection.json",
5
5
  "ng-add": {
6
6
  "save": "dependencies"
@@ -0,0 +1,12 @@
1
+ <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="3.57007" y="3.56995" width="40" height="40" rx="20" fill="#FEE2E2"/>
3
+ <rect x="3.57007" y="3.56995" width="40" height="40" rx="20" stroke="#FEE2E2" stroke-width="7.14"/>
4
+ <g clip-path="url(#clip0_1_149094)">
5
+ <path d="M23.5702 20.2366V23.5699M23.5702 26.9032H23.5785M31.9035 23.5699C31.9035 28.1723 28.1725 31.9032 23.5702 31.9032C18.9678 31.9032 15.2368 28.1723 15.2368 23.5699C15.2368 18.9675 18.9678 15.2366 23.5702 15.2366C28.1725 15.2366 31.9035 18.9675 31.9035 23.5699Z" stroke="#EF4444" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
6
+ </g>
7
+ <defs>
8
+ <clipPath id="clip0_1_149094">
9
+ <rect width="20" height="20" fill="white" transform="translate(13.5701 13.5699)"/>
10
+ </clipPath>
11
+ </defs>
12
+ </svg>
@@ -0,0 +1,226 @@
1
+ /* =========================================================================
2
+ bk-menu — simple responsive navigation menu.
3
+ Single light theme, matching the default bk-tabs styling:
4
+ text #141414, hover #EDEEF0, active #141414 bg with white text.
5
+ ========================================================================= */
6
+
7
+ .bk-menu {
8
+ --menu-bg: #ffffff;
9
+ --menu-text: #141414;
10
+ --menu-subtext: #6b7080;
11
+ --menu-hover-bg: #edeef0;
12
+ --menu-hover-text: #141414;
13
+ --menu-active-bg: #141414;
14
+ --menu-active-text: #ffffff;
15
+ --menu-border: #efeff1;
16
+ --menu-shadow: 0 7px 18px 0 rgba(0, 0, 0, 0.09);
17
+ --menu-radius: 8px;
18
+ --menu-disabled: 0.5;
19
+
20
+ display: block;
21
+ width: 100%;
22
+ max-width: 100%;
23
+ font-size: 0.875rem;
24
+ line-height: 1.25rem;
25
+ font-weight: 500;
26
+ letter-spacing: -0.28px;
27
+ background: var(--menu-bg);
28
+ color: var(--menu-text);
29
+ border: 1px solid var(--menu-border);
30
+ border-radius: var(--menu-radius);
31
+ /* Safe to clip to rounded corners: pop-up fly-outs are position:fixed and
32
+ escape this box entirely, so nothing gets cut off. */
33
+ overflow: hidden;
34
+ }
35
+
36
+ /* ---- Lists ---- */
37
+ .bk-menu__list,
38
+ .bk-menu__submenu {
39
+ list-style: none;
40
+ margin: 0;
41
+ padding: 0;
42
+ }
43
+
44
+ /* Scroll container: vertical scroll past max-height, horizontal scroll if a
45
+ deeply-indented inline row is wider than the menu. Fixed fly-outs escape it. */
46
+ .bk-menu__list--scroll {
47
+ overflow: auto;
48
+ }
49
+
50
+ /* Horizontal top-level row (menubar). Scrolls when crowded — fixed fly-outs are
51
+ unaffected by the overflow. */
52
+ .bk-menu--horizontal > .bk-menu__list {
53
+ display: flex;
54
+ flex-direction: row;
55
+ align-items: stretch;
56
+ overflow-x: auto;
57
+ }
58
+
59
+ /* ---- Item / button ---- */
60
+ .bk-menu__item {
61
+ position: relative; /* anchor for pop-up submenus */
62
+ }
63
+
64
+ .bk-menu__button {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 8px;
68
+ width: 100%;
69
+ padding: 10px 12px;
70
+ margin: 0;
71
+ border: 0;
72
+ background: transparent;
73
+ color: inherit;
74
+ font: inherit;
75
+ letter-spacing: inherit;
76
+ text-align: left;
77
+ cursor: pointer;
78
+ white-space: nowrap;
79
+ border-radius: 6px;
80
+ transition: background 0.1s ease, color 0.1s ease;
81
+ }
82
+
83
+ .bk-menu--horizontal > .bk-menu__list > .bk-menu__item > .bk-menu__button {
84
+ width: auto;
85
+ }
86
+
87
+ .bk-menu__button:hover:not(:disabled):not(.bk-menu__button--active) {
88
+ background: var(--menu-hover-bg);
89
+ color: var(--menu-hover-text);
90
+ }
91
+
92
+ .bk-menu__button--active {
93
+ background: var(--menu-active-bg);
94
+ color: var(--menu-active-text);
95
+ }
96
+
97
+ .bk-menu__button--disabled,
98
+ .bk-menu__button:disabled {
99
+ opacity: var(--menu-disabled);
100
+ cursor: not-allowed;
101
+ }
102
+
103
+ /* Nested (child) items use the muted sub-text colour. */
104
+ .bk-menu__submenu .bk-menu__button {
105
+ color: var(--menu-subtext);
106
+ font-weight: 400;
107
+ }
108
+
109
+ .bk-menu__submenu .bk-menu__button--active {
110
+ color: var(--menu-active-text);
111
+ }
112
+
113
+ /* ---- Icon (optional). Tinted monochrome when .bk-menu--tint. ---- */
114
+ .bk-menu__icon {
115
+ width: 16px;
116
+ height: 16px;
117
+ flex-shrink: 0;
118
+ object-fit: contain;
119
+ }
120
+
121
+ .bk-menu--tint .bk-menu__icon {
122
+ filter: brightness(0) saturate(0); /* → near-black, matches #141414 text */
123
+ }
124
+
125
+ /* Active row has a dark background → force a white icon for contrast. */
126
+ .bk-menu--tint .bk-menu__button--active .bk-menu__icon {
127
+ filter: brightness(0) invert(1);
128
+ }
129
+
130
+ .bk-menu__label {
131
+ flex: 1 1 auto;
132
+ min-width: 0;
133
+ overflow: hidden;
134
+ text-overflow: ellipsis;
135
+ }
136
+
137
+ .bk-menu--horizontal > .bk-menu__list > .bk-menu__item > .bk-menu__button > .bk-menu__label {
138
+ flex: 0 0 auto;
139
+ overflow: visible;
140
+ }
141
+
142
+ /* ---- Chevron ---- */
143
+ .bk-menu__chevron {
144
+ flex-shrink: 0;
145
+ transition: transform 0.18s ease;
146
+ opacity: 0.8;
147
+ }
148
+
149
+ /* Inline: rotate down → up on open. */
150
+ .bk-menu__chevron--open {
151
+ transform: rotate(180deg);
152
+ }
153
+
154
+ /* Pop-up fly-out: static caret pointing to where the panel opens (right). */
155
+ .bk-menu__chevron--right {
156
+ transform: rotate(-90deg);
157
+ }
158
+
159
+ /* =========================================================================
160
+ Inline submenus (accordion) — expand in place.
161
+ ========================================================================= */
162
+ .bk-menu__submenu--inline {
163
+ overflow: hidden;
164
+ max-height: 0;
165
+ transition: max-height 0.2s ease;
166
+ }
167
+
168
+ .bk-menu__submenu--inline.bk-menu__submenu--open {
169
+ max-height: 1000px; /* large enough to reveal nested content */
170
+ }
171
+
172
+ /* =========================================================================
173
+ Pop-up submenus — floating panels, hidden until open.
174
+ ========================================================================= */
175
+ .bk-menu__submenu--popup {
176
+ /* Fixed so the fly-out escapes the menu's overflow/scroll box and renders
177
+ outside the nav. Coordinates are set inline (top/left) from JS. */
178
+ position: fixed;
179
+ z-index: 1000;
180
+ min-width: 200px;
181
+ max-width: 280px;
182
+ max-height: calc(100vh - 16px);
183
+ overflow-y: auto;
184
+ background: var(--menu-bg);
185
+ border: 1px solid var(--menu-border);
186
+ border-radius: 12px;
187
+ box-shadow: var(--menu-shadow);
188
+ padding: 4px;
189
+ display: none;
190
+ }
191
+
192
+ .bk-menu__submenu--popup.bk-menu__submenu--open {
193
+ display: block;
194
+ }
195
+
196
+ /* Invisible bridges spanning the gap between a parent and its fly-out, so the
197
+ pointer stays "inside" the item while crossing — prevents hover flicker. */
198
+ .bk-menu__submenu--popup-right::before {
199
+ content: '';
200
+ position: absolute;
201
+ top: 0;
202
+ left: -6px;
203
+ width: 6px;
204
+ height: 100%;
205
+ }
206
+ .bk-menu__submenu--popup-down::before {
207
+ content: '';
208
+ position: absolute;
209
+ top: -6px;
210
+ left: 0;
211
+ width: 100%;
212
+ height: 6px;
213
+ }
214
+
215
+ /* =========================================================================
216
+ Responsive: stack a horizontal menu into a vertical one on small screens.
217
+ ========================================================================= */
218
+ @media (max-width: 640px) {
219
+ .bk-menu--horizontal > .bk-menu__list {
220
+ flex-direction: column;
221
+ overflow-x: visible;
222
+ }
223
+ .bk-menu--horizontal > .bk-menu__list > .bk-menu__item > .bk-menu__button {
224
+ width: 100%;
225
+ }
226
+ }
@@ -121,6 +121,28 @@
121
121
  color: #15191E;
122
122
  }
123
123
 
124
+ /* Segmented error pill — an icon alone reads too subtly here, so give the pill
125
+ a red tint, border and text. Placed after the base/active segmented rules so
126
+ it wins on equal specificity; the active+error combo uses 3 classes to win. */
127
+ .tabs-button--segmented.tabs-button--error {
128
+ background: #FEE2E2;
129
+ border-color: #FCA5A5;
130
+ color: #C10007;
131
+ }
132
+
133
+ .tabs-button--segmented.tabs-button--error.tabs-button--active {
134
+ background: #FFFFFF;
135
+ border-color: #C10007;
136
+ color: #C10007;
137
+ }
138
+
139
+ /* Keep the error look on hover (the generic pill hover would otherwise win). */
140
+ .tabs-button--segmented.tabs-button--error:hover:not(:disabled):not(.tabs-button--active) {
141
+ background: #FEE2E2;
142
+ border-color: #C10007;
143
+ color: #C10007;
144
+ }
145
+
124
146
  /* Segmented + vertical: single-column grid = stacked full-width pills.
125
147
  Placed after the base segmented rules so it wins on equal specificity. */
126
148
  .tabs-list--segmented-vertical {
@@ -132,4 +154,3 @@
132
154
  @apply justify-start text-left;
133
155
  }
134
156
 
135
- /* Testing */