ecabs-components 1.1.99 → 1.2.1

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.
@@ -3,21 +3,19 @@ export interface SidebarMenuItem<TEnv = unknown, TRole = unknown> {
3
3
  icon?: string;
4
4
  url?: string;
5
5
  expand?: boolean;
6
- subItems?: SidebarMenuItem[];
7
- permissions?: PermissionValueEnum<string>[];
6
+ subItems?: SidebarMenuItem<TEnv, TRole>[];
7
+ permissions?: string[];
8
8
  iconResource?: SidebarIconResource;
9
9
  badge?: string;
10
10
  isVisible?: (context: MenuItemVisibilityContext<TEnv, TRole>) => boolean;
11
+ isBadgeVisible?: (context: MenuItemVisibilityContext<TEnv, TRole>) => boolean;
11
12
  }
12
13
  export interface MenuItemVisibilityContext<TEnv, TRole> {
13
14
  environment: TEnv;
14
- role: TRole;
15
+ role?: TRole;
16
+ tenantFeatures?: string[];
15
17
  }
16
18
  export interface SidebarIconResource {
17
19
  path: string;
18
20
  name: string;
19
21
  }
20
- interface PermissionValueEnum<T extends string> {
21
- values: Record<T, string>;
22
- }
23
- export {};
@@ -1,2 +1,11 @@
1
- import { SidebarMenuItem } from '../models/sidebar.models';
1
+ import { MenuItemVisibilityContext, SidebarMenuItem } from '../models/sidebar.models';
2
2
  export declare function matchMenuToUrl(url: string, menu: SidebarMenuItem[]): SidebarMenuItem;
3
+ /**
4
+ * Returns copies of the menu items the user should see, never changing `menu`.
5
+ *
6
+ * Permissions are checked only when `permissions` is given: `undefined` skips the
7
+ * check, while `[]` checks against a user with no claims. An item shows when it has
8
+ * no `permissions`, includes `'allow'`, or the user holds any one of them.
9
+ * Then each item's `isVisible` and `isBadgeVisible` run, and groups left empty are removed.
10
+ */
11
+ export declare function filterMenuItems<TEnv, TRole>(menu: SidebarMenuItem<TEnv, TRole>[], context: MenuItemVisibilityContext<TEnv, TRole>, permissions?: string[]): SidebarMenuItem<TEnv, TRole>[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ecabs-components",
3
- "version": "1.1.99",
3
+ "version": "1.2.1",
4
4
  "peerDependencies": {
5
5
  "@angular/animations": "^16.2.12",
6
6
  "@angular/common": "^16.2.12",
package/public-api.d.ts CHANGED
@@ -149,6 +149,7 @@ export * from './lib/base/utils/object-utils';
149
149
  export * from './lib/base/utils/phone-number.utils';
150
150
  export * from './lib/base/utils/icon.utils';
151
151
  export * from './lib/base/utils/select.utils';
152
+ export * from './lib/base/utils/menu-utils';
152
153
  export * from './lib/base/consts/badge.consts';
153
154
  export * from './lib/base/consts/status-badge.consts';
154
155
  export * from './lib/base/consts/icon.consts';
@@ -11,6 +11,12 @@
11
11
  .mdc-dialog__actions {
12
12
  padding: calc-rem(0 24px 24px);
13
13
  justify-content: end !important;
14
+
15
+ @include media-q(x-small) {
16
+ &.btn__group {
17
+ align-items: stretch;
18
+ }
19
+ }
14
20
  }
15
21
 
16
22
  .mdc-dialog__content {
@@ -198,13 +198,27 @@
198
198
  /* #Group */
199
199
  @include e(group) {
200
200
  display: flex;
201
+ flex-wrap: wrap;
201
202
  width: 100%;
202
203
  align-items: center;
203
204
  column-gap: 1rem;
205
+ row-gap: 1rem;
204
206
 
205
- @include media-q(small) {
207
+ // A group inside another group holds buttons that belong together, such as Cancel and Save beside a Delete.
208
+ // Beside other items it sizes to its buttons; alone in its row it fills the row, so its own justify applies.
209
+ & > & {
210
+ width: auto;
211
+ margin-top: 0;
212
+
213
+ &:only-child {
214
+ width: 100%;
215
+ }
216
+ }
217
+
218
+ @include media-q(x-small) {
206
219
  display: flex;
207
220
  flex-direction: column;
221
+ align-items: stretch;
208
222
  gap: 1.2rem;
209
223
  }
210
224
 
@@ -212,7 +226,7 @@
212
226
 
213
227
  // Button group
214
228
  @include m(item) {
215
- @include media-q(small) {
229
+ @include media-q(x-small) {
216
230
  width: 100%;
217
231
  margin-right: 0;
218
232
  }
@@ -1,43 +1,47 @@
1
- @use "sass:map";
2
-
3
- // Emits no CSS, so apps can `@use "ecabs-components/breakpoints"` from component styles.
4
- // PHONE_MEDIA_QUERY in base/consts/breakpoints.consts.ts must match 'md' here.
5
-
6
- // #Viewport Breakpoints
7
- $breakpoints: (
8
- xs: 0,
9
- sm: 576px,
10
- md: 768px,
11
- lg: 992px,
12
- xl: 1200px,
13
- xxl: 1400px
14
- );
15
-
16
- // ==========================================================================
17
- // Media Query Functions
18
- // ==========================================================================
19
- @mixin media-q($break) {
20
- @if $break == 'small' {
21
- @media (min-width: map.get($breakpoints, 'xs')) and (max-width: map.get($breakpoints, 'md') - 0.02px) {
22
- @content;
23
- }
24
- } @else if $break == 'medium' {
25
- @media (min-width: map.get($breakpoints, 'md')) {
26
- @content;
27
- }
28
- } @else if $break == 'large' {
29
- @media (min-width: map.get($breakpoints, 'lg')) {
30
- @content;
31
- }
32
- } @else if $break == 'x-large' {
33
- @media (min-width: map.get($breakpoints, 'xl')) {
34
- @content;
35
- }
36
- } @else if $break == 'xx-large' {
37
- @media (min-width: map.get($breakpoints, 'xxl')) {
38
- @content;
39
- }
40
- } @else {
41
- @error '"#{$break}" is not a valid breakpoint. Please enter a supported value (e.g. "small", "medium" or "large")';
42
- }
43
- }
1
+ @use "sass:map";
2
+
3
+ // Emits no CSS, so apps can `@use "ecabs-components/breakpoints"` from component styles.
4
+ // PHONE_MEDIA_QUERY in base/consts/breakpoints.consts.ts must match 'md' here.
5
+
6
+ // #Viewport Breakpoints
7
+ $breakpoints: (
8
+ xs: 0,
9
+ sm: 576px,
10
+ md: 768px,
11
+ lg: 992px,
12
+ xl: 1200px,
13
+ xxl: 1400px
14
+ );
15
+
16
+ // ==========================================================================
17
+ // Media Query Functions
18
+ // ==========================================================================
19
+ @mixin media-q($break) {
20
+ @if $break == 'x-small' {
21
+ @media (max-width: map.get($breakpoints, 'sm') - 0.02px) {
22
+ @content;
23
+ }
24
+ } @else if $break == 'small' {
25
+ @media (min-width: map.get($breakpoints, 'xs')) and (max-width: map.get($breakpoints, 'md') - 0.02px) {
26
+ @content;
27
+ }
28
+ } @else if $break == 'medium' {
29
+ @media (min-width: map.get($breakpoints, 'md')) {
30
+ @content;
31
+ }
32
+ } @else if $break == 'large' {
33
+ @media (min-width: map.get($breakpoints, 'lg')) {
34
+ @content;
35
+ }
36
+ } @else if $break == 'x-large' {
37
+ @media (min-width: map.get($breakpoints, 'xl')) {
38
+ @content;
39
+ }
40
+ } @else if $break == 'xx-large' {
41
+ @media (min-width: map.get($breakpoints, 'xxl')) {
42
+ @content;
43
+ }
44
+ } @else {
45
+ @error '"#{$break}" is not a valid breakpoint. Please enter a supported value (e.g. "x-small", "small", "medium" or "large")';
46
+ }
47
+ }