@brickclay-org/ui 0.1.67 → 0.1.69

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
@@ -866,7 +866,7 @@ declare class BkSelect implements ControlValueAccessor, AfterViewInit, OnDestroy
866
866
  disabled: i0.ModelSignal<boolean>;
867
867
  loading: i0.InputSignal<boolean>;
868
868
  closeOnSelect: i0.InputSignal<boolean>;
869
- dropdownPosition: i0.InputSignal<"top" | "bottom">;
869
+ dropdownPosition: i0.InputSignal<"bottom" | "top">;
870
870
  hasError: boolean;
871
871
  errorMessage: string;
872
872
  appendToBody: i0.InputSignal<boolean>;
@@ -1104,6 +1104,21 @@ declare class BkInputChips implements ControlValueAccessor, AfterViewInit {
1104
1104
  }
1105
1105
 
1106
1106
  type TabIconDirection = 'left' | 'right';
1107
+ type TabsOrientation = 'horizontal' | 'vertical';
1108
+ type TabsVariant = 'default' | 'segmented';
1109
+ /**
1110
+ * Per-usage CSS classes for the 'segmented' variant.
1111
+ * Pass Tailwind classes (not raw colors). Because the component uses
1112
+ * emulated encapsulation, its default color rules out-specify plain
1113
+ * utilities — so use the important prefix, e.g. '!bg-white', '!text-black'.
1114
+ * Any field left undefined keeps the default design token from tabs.css.
1115
+ */
1116
+ interface TabsColors {
1117
+ wrapper?: string;
1118
+ active?: string;
1119
+ activeText?: string;
1120
+ inactive?: string;
1121
+ }
1107
1122
  interface TabItem {
1108
1123
  id: string;
1109
1124
  label: string;
@@ -1120,12 +1135,19 @@ declare class BkTabs {
1120
1135
  list: TabItem[];
1121
1136
  activeTabId: string;
1122
1137
  disabled: boolean;
1138
+ orientation: TabsOrientation;
1139
+ variant: TabsVariant;
1140
+ colors: TabsColors;
1141
+ get isVertical(): boolean;
1142
+ get isSegmented(): boolean;
1143
+ get wrapperClass(): string;
1144
+ segmentedTabClass(tab: TabItem): string;
1123
1145
  change: EventEmitter<TabItem>;
1124
1146
  setActiveTab(tab: TabItem): void;
1125
1147
  isActive(tabId: string): boolean;
1126
1148
  getTabIcon(tab: TabItem): string | undefined;
1127
1149
  static ɵfac: i0.ɵɵFactoryDeclaration<BkTabs, never>;
1128
- static ɵcmp: i0.ɵɵComponentDeclaration<BkTabs, "bk-tabs", never, { "list": { "alias": "list"; "required": false; }; "activeTabId": { "alias": "activeTabId"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "change": "change"; }, never, never, true, never>;
1150
+ 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>;
1129
1151
  }
1130
1152
 
1131
1153
  /**
@@ -1941,7 +1963,7 @@ declare class BkHierarchicalSelect implements ControlValueAccessor {
1941
1963
  /** When true, dropdown is positioned fixed and sized to the trigger (use inside modals/popups). */
1942
1964
  appendToBody: i0.InputSignal<boolean>;
1943
1965
  /** Open above or below the trigger (also used when appendToBody is true for fixed coordinates). */
1944
- dropdownPosition: i0.InputSignal<"top" | "bottom">;
1966
+ dropdownPosition: i0.InputSignal<"bottom" | "top">;
1945
1967
  /** Key for option color (e.g. "color"). When set, option label and selected value use this color. */
1946
1968
  colorKey: i0.InputSignal<string>;
1947
1969
  /** Whether to show clear button when a value is selected. */
@@ -2290,5 +2312,76 @@ declare class BkLoader {
2290
2312
  static ɵcmp: i0.ɵɵComponentDeclaration<BkLoader, "bk-loader", never, { "loading": { "alias": "loading"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; }, {}, never, never, true, never>;
2291
2313
  }
2292
2314
 
2293
- 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, 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 };
2294
- 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, FileState, GroupItem, GroupMode, HierarchicalNode, IconButtonSize, IconButtonVariant, IconOrientation, PillColor, PillSize, PillVariant, ScheduledDateSelection, SortDirection, SpinnerSize, TabIconDirection, TabItem, TableAction, TableBadge, TableColumn, TableIcon, TimeConfiguration, ToastConfig, ToastMessage, ToastMethodOptions, ToastPosition, ToastSeverity };
2315
+ type DropdownVariant = 'black' | 'white';
2316
+ type DropdownSize = 'sm' | 'md' | 'lg';
2317
+ type DropdownTrigger = 'click' | 'hover';
2318
+ type DropdownPlacement = 'bottomLeft' | 'bottom' | 'bottomRight' | 'topLeft' | 'top' | 'topRight';
2319
+ interface DropdownItem {
2320
+ id?: string | number;
2321
+ label?: string;
2322
+ icon?: string;
2323
+ disabled?: boolean;
2324
+ divider?: boolean;
2325
+ children?: DropdownItem[];
2326
+ }
2327
+ declare class BkDropdown {
2328
+ private readonly host;
2329
+ /** Text shown on the trigger button. */
2330
+ label: string;
2331
+ /** Menu items (supports divider / disabled / children). */
2332
+ items: DropdownItem[];
2333
+ /** Black (dark) or white (light, bordered) — mirrors the segment-tab look. */
2334
+ variant: DropdownVariant;
2335
+ /** Trigger size. */
2336
+ size: DropdownSize;
2337
+ /** Open on click or on hover. */
2338
+ trigger: DropdownTrigger;
2339
+ /** One of 6 placements for the menu. */
2340
+ placement: DropdownPlacement;
2341
+ /** Show the caret (▾) on the trigger. Rotates when open. */
2342
+ arrow: boolean;
2343
+ /** Split button: a primary action + a separate caret that opens the menu. */
2344
+ splitButton: boolean;
2345
+ /** Currently selected item id — the matching item shows a tick. */
2346
+ selectedId?: string | number;
2347
+ /** Disable the whole control. */
2348
+ disabled: boolean;
2349
+ /** Optional leading icon on the trigger. */
2350
+ iconSrc?: string;
2351
+ /** Extra classes appended to the trigger button. */
2352
+ customClass: string;
2353
+ /** Emits when a (non-disabled) leaf item is chosen. */
2354
+ select: EventEmitter<DropdownItem>;
2355
+ /** Emits the open/closed state whenever it changes. */
2356
+ openChange: EventEmitter<boolean>;
2357
+ /** Split button primary-action click. */
2358
+ buttonClick: EventEmitter<Event>;
2359
+ open: boolean;
2360
+ private closeTimer;
2361
+ constructor(host: ElementRef<HTMLElement>);
2362
+ toggle(): void;
2363
+ onPrimaryClick(event: Event): void;
2364
+ selectItem(item: DropdownItem, event: Event): void;
2365
+ isSelected(item: DropdownItem): boolean;
2366
+ get hasSubmenus(): boolean;
2367
+ private setOpen;
2368
+ onHoverEnter(): void;
2369
+ onHoverLeave(): void;
2370
+ /**
2371
+ * When a parent item is hovered, decide whether its submenu should open to
2372
+ * the right (default) or flip to the left if it would overflow the viewport.
2373
+ */
2374
+ onSubmenuEnter(event: MouseEvent): void;
2375
+ private clearCloseTimer;
2376
+ onDocumentClick(event: MouseEvent): void;
2377
+ onEscape(): void;
2378
+ get triggerClasses(): string;
2379
+ get caretSizeClass(): string;
2380
+ /** Position classes for the menu panel per placement. */
2381
+ get menuPositionClass(): string;
2382
+ static ɵfac: i0.ɵɵFactoryDeclaration<BkDropdown, never>;
2383
+ 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>;
2384
+ }
2385
+
2386
+ 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 };
2387
+ 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brickclay-org/ui",
3
- "version": "0.1.67",
3
+ "version": "0.1.69",
4
4
  "schematics": "./schematics/collection.json",
5
5
  "ng-add": {
6
6
  "save": "dependencies"
@@ -0,0 +1,156 @@
1
+ /* Root — anchor for the absolutely-positioned menu */
2
+ .bk-dd {
3
+ @apply relative inline-block;
4
+ }
5
+
6
+ /* =======================================================
7
+ Trigger button — mirrors app-button (rounded, medium,
8
+ bordered) with black / white variants and sizes.
9
+ ======================================================= */
10
+ .bk-dd-trigger {
11
+ @apply inline-flex items-center justify-center gap-1.5 border rounded-md font-medium cursor-pointer transition-colors duration-100 outline-none whitespace-nowrap tracking-[-0.28];
12
+ }
13
+
14
+ /* Sizes */
15
+ .bk-dd-trigger--sm {
16
+ @apply text-xs px-2.5 py-1.5 leading-3;
17
+ }
18
+
19
+ .bk-dd-trigger--md {
20
+ @apply text-sm px-3 py-2 leading-[14px];
21
+ }
22
+
23
+ .bk-dd-trigger--lg {
24
+ @apply text-base px-4 py-2.5 leading-4;
25
+ }
26
+
27
+ /* Black variant (like the active segment tab) */
28
+ .bk-dd-trigger--black {
29
+ @apply bg-[#141414] text-white border-transparent;
30
+ }
31
+
32
+ .bk-dd-trigger--black:hover:not(:disabled) {
33
+ @apply bg-[#2A2A2A];
34
+ }
35
+
36
+ /* White variant (light, bordered — like an inactive segment tab) */
37
+ .bk-dd-trigger--white {
38
+ @apply bg-white text-[#141414] border-[#E3E3E7];
39
+ }
40
+
41
+ .bk-dd-trigger--white:hover:not(:disabled) {
42
+ @apply bg-[#F9FAFA];
43
+ }
44
+
45
+ /* Disabled */
46
+ .bk-dd-trigger--disabled {
47
+ @apply opacity-50 cursor-not-allowed;
48
+ }
49
+
50
+ .bk-dd-label {
51
+ @apply whitespace-nowrap;
52
+ }
53
+
54
+ /* Caret rotates 180° when the menu is open */
55
+ .bk-dd-caret {
56
+ @apply transition-transform duration-200;
57
+ }
58
+
59
+ .bk-dd--open .bk-dd-caret {
60
+ @apply rotate-180;
61
+ }
62
+
63
+ /* =======================================================
64
+ Split button (Button with dropdown menu)
65
+ ======================================================= */
66
+ .bk-dd-split {
67
+ @apply inline-flex items-stretch;
68
+ }
69
+
70
+ /* main action: square off the right corners */
71
+ .bk-dd-split-main {
72
+ @apply rounded-r-none;
73
+ }
74
+
75
+ /* caret side: square off the left corners + a divider seam */
76
+ .bk-dd-split-caret {
77
+ @apply rounded-l-none border-l-0 px-2;
78
+ }
79
+
80
+ .bk-dd-split-caret.bk-dd-trigger--black {
81
+ @apply border-l border-l-[#2A2A2A];
82
+ }
83
+
84
+ .bk-dd-split-caret.bk-dd-trigger--white {
85
+ @apply border-l border-l-[#E3E3E7];
86
+ }
87
+
88
+ .bk-dd-split--disabled {
89
+ @apply opacity-50 pointer-events-none;
90
+ }
91
+
92
+ /* =======================================================
93
+ Menu panel — matches the bk-select dropdown panel look.
94
+ ======================================================= */
95
+ .bk-dd-menu {
96
+ @apply absolute z-[100] min-w-[10rem] max-w-[16rem] bg-white border border-[#E3E3E7] rounded-xl shadow-lg p-2.5;
97
+ }
98
+
99
+ .bk-dd-list {
100
+ @apply relative z-10 list-none m-0 p-0 flex flex-col gap-0.5;
101
+ }
102
+
103
+ /* Scroll only when there are no submenus (see hasSubmenus). */
104
+ .bk-dd-list--scroll {
105
+ @apply max-h-[16rem] overflow-y-auto;
106
+ }
107
+
108
+ /* Menu item */
109
+ .bk-dd-li {
110
+ @apply relative;
111
+ }
112
+
113
+ .bk-dd-item {
114
+ @apply flex items-center gap-2 w-full text-left p-2.5 rounded-md text-sm font-normal text-[#141414] bg-transparent cursor-pointer transition-colors;
115
+ }
116
+
117
+ .bk-dd-item:hover:not(:disabled) {
118
+ @apply bg-[#F8F8F8];
119
+ }
120
+
121
+ .bk-dd-item--disabled {
122
+ @apply opacity-50 cursor-not-allowed;
123
+ }
124
+
125
+ .bk-dd-item-label {
126
+ @apply flex-1 min-w-0 truncate;
127
+ }
128
+
129
+ .bk-dd-item-caret {
130
+ @apply text-[#6B7080];
131
+ }
132
+
133
+ .bk-dd-check {
134
+ @apply text-[#141414];
135
+ }
136
+
137
+ /* Divider — span the panel padding */
138
+ .bk-dd-divider {
139
+ @apply -mx-2.5 h-px bg-[#E3E3E7];
140
+ }
141
+
142
+ /* =======================================================
143
+ Cascading submenu — revealed on hover of a parent item
144
+ ======================================================= */
145
+ .bk-dd-submenu {
146
+ @apply absolute top-0 left-full ml-1 hidden min-w-[10rem] max-w-[16rem] list-none m-0 p-2.5 flex-col gap-0.5 bg-white border border-[#E3E3E7] rounded-xl shadow-lg;
147
+ }
148
+
149
+ .bk-dd-li--parent:hover>.bk-dd-submenu {
150
+ @apply flex;
151
+ }
152
+
153
+ /* Flip to the left when there isn't room on the right (class set via JS on hover). */
154
+ .bk-dd-submenu--flip>.bk-dd-submenu {
155
+ @apply left-auto right-full ml-0 mr-1;
156
+ }
@@ -3,14 +3,23 @@
3
3
  @apply w-full;
4
4
  }
5
5
 
6
- /* Tabs List */
6
+ /* Tabs List
7
+ Grid layout: columns flow horizontally and size to content
8
+ (auto-cols-max), matching the old flex row while giving grid control. */
7
9
  .tabs-list {
8
- @apply flex gap-0 list-none m-0 px-0 py-0.5;
10
+ @apply grid grid-flow-col auto-cols-max gap-0 list-none m-0 px-0 py-0.5;
9
11
  }
10
12
 
11
13
  /* Tab Item */
12
14
  .tabs-item {
13
- @apply flex-shrink-0;
15
+ @apply min-w-0;
16
+ }
17
+
18
+ /* Vertical (default variant): single-column grid = stacked full-width tabs.
19
+ Defined after the base .tabs-list so grid-flow-row reliably overrides the
20
+ base grid-flow-col (otherwise items flow into columns = horizontal). */
21
+ .tabs-list--vertical {
22
+ @apply grid-cols-1 grid-flow-row auto-rows-max;
14
23
  }
15
24
 
16
25
  /* Tab Button - Base Styles */
@@ -62,3 +71,54 @@
62
71
  @apply whitespace-nowrap;
63
72
  }
64
73
 
74
+
75
+ /* =========================================================
76
+ Segmented variant (pill-in-a-track)
77
+ Colors are driven by CSS vars set per-usage via [colors],
78
+ falling back to the default design tokens.
79
+ ========================================================= */
80
+
81
+ /* Track / wrapper — default background; override via colors.wrapper (use ! classes). */
82
+ .tabs-container--segmented {
83
+ @apply p-[3px] rounded-md w-full md:w-auto;
84
+ background: #54578E12;
85
+ }
86
+
87
+ /* Pill row — equal-width columns (auto-cols-fr) replace the old flex-1. */
88
+ .tabs-list--segmented {
89
+ @apply grid grid-flow-col auto-cols-fr items-center gap-2 rounded-md font-medium text-sm leading-4 w-full sm:w-auto py-0;
90
+ color: #6B7080;
91
+ }
92
+
93
+ /* Pill button — min-width keeps short labels even, but lets icon/long
94
+ labels grow instead of clipping the icon. Default inactive text; override
95
+ via colors.inactive (use ! classes). */
96
+ .tabs-button--segmented {
97
+ @apply border border-transparent px-3 sm:min-w-[5rem] py-1.5 w-full text-center justify-center rounded;
98
+ color: #6B7080;
99
+ }
100
+
101
+ /* Pill hover (not on active / disabled) */
102
+ .tabs-button--segmented:hover:not(:disabled):not(.tabs-button--active) {
103
+ border-color: #42578A26;
104
+ background: #FFFFFF;
105
+ color: #15191E;
106
+ }
107
+
108
+ /* Pill active — default colors; override via colors.active / colors.activeText
109
+ (use ! classes, which out-specify this scoped rule). */
110
+ .tabs-button--segmented.tabs-button--active {
111
+ background: #FFFFFF;
112
+ color: #15191E;
113
+ }
114
+
115
+ /* Segmented + vertical: single-column grid = stacked full-width pills.
116
+ Placed after the base segmented rules so it wins on equal specificity. */
117
+ .tabs-list--segmented-vertical {
118
+ @apply grid-cols-1 grid-flow-row auto-rows-max gap-1;
119
+ }
120
+
121
+ /* Left-align pill content in the vertical segmented layout */
122
+ .tabs-list--segmented-vertical .tabs-button--segmented {
123
+ @apply justify-start text-left;
124
+ }
package/src/styles.css CHANGED
@@ -25,3 +25,4 @@
25
25
  @import './lib/file-card/file-card.css';
26
26
  @import './lib/pagination/pagination.css';
27
27
  @import './lib/loader/loader.css';
28
+ @import './lib/dropdown/dropdown.css';