Skip to content

Commit c7cadc3

Browse files
authored
feat(cdk-experimental/menu): Add menu skeleton and build scripts (#19583)
* feat(cdk-experimental/menu): Add menu skeleton and build scripts Configure bazel scripts for a cdk menu feature along with the general structure identifying the set of directives which make it up * feat(cdk-experimental/menu): Configure dev-app Configure dev-app for cdk-experimental/menu * build: Allow indirect circular dependency between menu and menu-item A CdkMenuItem opens a CdkMenuPanel and therefore must reference it. A CdkMenuPanel contains a CdkMenu and therefore must reference it. A CdkMenu contains CdkMenuItem's and therefore must reference it. * feat(cdk-experimental/menu): Quote all host keys * feat(cdk-experimental/menu): Add missing aria-attributes * feat(cdk-experimental/menu): Clear up CdkMenuItem comment * feat(cdk-experimental/menu): Remove unused build dep * feat(cdk-experimental/menu): Fix codeowners Move from material-experimental section to cdk-experimental * feat(cdk-experimental/menu): Grammer fix * feat(cdk-experimental/menu): explicitly specify the return when null and boolean * feat(cdk-experimental/menu): Clear up documentation/comments * feat(cdk-experimental/menu): Make cdkMenuOrientation comment more clear * feat(cdk-experimental/menu): Make orientation attribute public for consistency * feat(cdk-experimental/menu): Remove unnecessary comment for role binding * feat(cdk-experimental/menu): Fix orientation attribute on host binding typo * feat(cdk-experimental/menu): Refactor `orientation` property comment for clarity * feat(cdk-experimental/menu): Refactor event emitter types Emitters self complete when used with @output * feat(cdk-experimental/menu): Remove documentation to be added once feature is complete * feat(cdk-experimental/menu): Rename opensMenu method hasSubmenu specifies that it refers to the menu it opens and not its parent * feat(cdk-experimental/menu): Use getter function not property for aria-checked Getter property generates more code than a getter function - prefer to use a function. * feat(cdk-experimental/menu): refactor MenuGroup doc for clarity * feat(cdk-experimental/menu): add @jelbourn to CODEOWNERS for cdk-experimental/menu * feat(cdk-experimental/menu): coerce MenuItem checked state to boolean * feat(cdk-experimental/menu): nit: rename val to value
1 parent bde24ed commit c7cadc3

20 files changed

+344
-0
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
/src/cdk-experimental/* @jelbourn
126126
/src/cdk-experimental/column-resize/** @kseamon @andrewseguin
127127
/src/cdk-experimental/dialog/** @jelbourn @crisbeto
128+
/src/cdk-experimental/menu/** @jelbourn @andy9775
128129
/src/cdk-experimental/popover-edit/** @kseamon @andrewseguin
129130
/src/cdk-experimental/scrolling/** @mmalerba
130131

@@ -141,6 +142,7 @@
141142
/src/dev-app/button-toggle/** @jelbourn
142143
/src/dev-app/button/** @jelbourn
143144
/src/dev-app/card/** @jelbourn
145+
/src/dev-app/cdk-experimental-menu/** @jelbourn @andy9775
144146
/src/dev-app/checkbox/** @jelbourn @devversion
145147
/src/dev-app/chips/** @jelbourn
146148
/src/dev-app/clipboard/** @jelbourn @xkxx

goldens/ts-circular-deps.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
"src/cdk-experimental/dialog/dialog-config.ts",
44
"src/cdk-experimental/dialog/dialog-container.ts"
55
],
6+
[
7+
"src/cdk-experimental/menu/menu-item.ts",
8+
"src/cdk-experimental/menu/menu-panel.ts",
9+
"src/cdk-experimental/menu/menu.ts"
10+
],
611
[
712
"src/cdk-experimental/popover-edit/edit-event-dispatcher.ts",
813
"src/cdk-experimental/popover-edit/edit-ref.ts"

src/cdk-experimental/config.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
CDK_EXPERIMENTAL_ENTRYPOINTS = [
33
"column-resize",
44
"dialog",
5+
"menu",
56
"popover-edit",
67
"scrolling",
78
]

src/cdk-experimental/menu/BUILD.bazel

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
load("//tools:defaults.bzl", "ng_module")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ng_module(
6+
name = "menu",
7+
srcs = glob(
8+
["**/*.ts"],
9+
exclude = ["**/*.spec.ts"],
10+
),
11+
module_name = "@angular/cdk-experimental/menu",
12+
deps = [
13+
"//src/cdk/coercion",
14+
"@npm//@angular/core",
15+
"@npm//rxjs",
16+
],
17+
)

src/cdk-experimental/menu/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export * from './public-api';

src/cdk-experimental/menu/menu-bar.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Directive, Input} from '@angular/core';
10+
11+
/**
12+
* Directive applied to an element which configures it as a MenuBar by setting the appropriate
13+
* role, aria attributes, and accessable keyboard and mouse handling logic. The component that
14+
* this directive is applied to should contain components marked with CdkMenuItem.
15+
*
16+
*/
17+
@Directive({
18+
selector: '[cdkMenuBar]',
19+
exportAs: 'cdkMenuBar',
20+
host: {
21+
'role': 'menubar',
22+
'[attr.aria-orientation]': 'orientation',
23+
},
24+
})
25+
export class CdkMenuBar {
26+
/**
27+
* Sets the aria-orientation attribute and determines where sub-menus will be opened.
28+
* Does not affect styling/layout.
29+
*/
30+
@Input('cdkMenuBarOrientation') orientation: 'horizontal' | 'vertical' = 'horizontal';
31+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Directive, Output, EventEmitter} from '@angular/core';
10+
import {CdkMenuItem} from './menu-item';
11+
12+
/**
13+
* Directive which acts as a grouping container for `CdkMenuItem` instances with
14+
* `role="menuitemradio"`, similar to a `role="radiogroup"` element.
15+
*/
16+
@Directive({
17+
selector: '[cdkMenuGroup]',
18+
exportAs: 'cdkMenuGroup',
19+
host: {
20+
'role': 'group',
21+
},
22+
})
23+
export class CdkMenuGroup {
24+
/** Emits the element when checkbox or radiobutton state changed */
25+
@Output() change: EventEmitter<CdkMenuItem> = new EventEmitter();
26+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Directive, Output, Input, EventEmitter} from '@angular/core';
10+
import {CdkMenuPanel} from './menu-panel';
11+
import {coerceBooleanProperty, BooleanInput} from '@angular/cdk/coercion';
12+
13+
/**
14+
* Directive which provides behavior for an element which when clicked:
15+
* If located in a CdkMenuBar:
16+
* - opens up an attached submenu
17+
*
18+
* If located in a CdkMenu/CdkMenuGroup, one of:
19+
* - executes the user defined click handler
20+
* - toggles its checkbox state
21+
* - toggles its radio button state (in relation to siblings)
22+
*
23+
* If it's in a CdkMenu and it triggers a sub-menu, hovering over the
24+
* CdkMenuItem will open the submenu.
25+
*
26+
*/
27+
@Directive({
28+
selector: '[cdkMenuItem], [cdkMenuTriggerFor]',
29+
exportAs: 'cdkMenuItem',
30+
host: {
31+
'type': 'button',
32+
'[attr.role]': 'role',
33+
'[attr.aria-checked]': '_getAriaChecked()',
34+
},
35+
})
36+
export class CdkMenuItem {
37+
/** Template reference variable to the menu this trigger opens */
38+
@Input('cdkMenuTriggerFor') _menuPanel: CdkMenuPanel;
39+
40+
/** ARIA role for the menu item. */
41+
@Input() role: 'menuitem' | 'menuitemradio' | 'menuitemcheckbox' = 'menuitem';
42+
43+
/** Whether the checkbox or radiobutton is checked */
44+
@Input()
45+
get checked() {
46+
return this._checked;
47+
}
48+
set checked(value: boolean) {
49+
this._checked = coerceBooleanProperty(value);
50+
}
51+
private _checked = false;
52+
53+
/** Emits when the attached submenu is opened */
54+
@Output() opened: EventEmitter<void> = new EventEmitter();
55+
56+
/** get the aria-checked value only if element is `menuitemradio` or `menuitemcheckbox` */
57+
_getAriaChecked(): boolean | null {
58+
if (this.role === 'menuitem') {
59+
return null;
60+
}
61+
return this.checked;
62+
}
63+
64+
/** Whether the menu item opens a menu */
65+
hasSubmenu() {
66+
return !!this._menuPanel;
67+
}
68+
69+
static ngAcceptInputType_checked: BooleanInput;
70+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {NgModule} from '@angular/core';
10+
import {CdkMenu} from './menu';
11+
import {CdkMenuBar} from './menu-bar';
12+
import {CdkMenuPanel} from './menu-panel';
13+
import {CdkMenuItem} from './menu-item';
14+
import {CdkMenuGroup} from './menu-group';
15+
16+
const EXPORTED_DECLARATIONS = [CdkMenuBar, CdkMenu, CdkMenuPanel, CdkMenuItem, CdkMenuGroup];
17+
@NgModule({
18+
exports: EXPORTED_DECLARATIONS,
19+
declarations: EXPORTED_DECLARATIONS,
20+
})
21+
export class CdkMenuModule {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Directive} from '@angular/core';
10+
import {CdkMenu} from './menu';
11+
12+
/**
13+
* Directive applied to an ng-template which wraps a CdkMenu and provides a reference to the
14+
* child element it wraps which allows for opening of the CdkMenu in an overlay.
15+
*/
16+
@Directive({selector: 'ng-template[cdkMenuPanel]', exportAs: 'cdkMenuPanel'})
17+
export class CdkMenuPanel {
18+
/** Reference to the child menu component */
19+
_menu: CdkMenu;
20+
}

0 commit comments

Comments
 (0)