-
Notifications
You must be signed in to change notification settings - Fork 6.8k
feat(cdk-experimental/menu): Add menu skeleton and build scripts #19583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 16 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
b8e838b
feat(cdk-experimental/menu): Add menu skeleton and build scripts
andy9775 187bc6e
feat(cdk-experimental/menu): Configure dev-app
andy9775 7b010a9
build: Allow indirect circular dependency between menu and menu-item
andy9775 5fbb865
feat(cdk-experimental/menu): Quote all host keys
andy9775 9118b14
feat(cdk-experimental/menu): Add missing aria-attributes
andy9775 c039f66
feat(cdk-experimental/menu): Clear up CdkMenuItem comment
andy9775 235da65
feat(cdk-experimental/menu): Remove unused build dep
andy9775 645f0d7
feat(cdk-experimental/menu): Fix codeowners
andy9775 2ac2cf3
feat(cdk-experimental/menu): Grammer fix
andy9775 e4e8c7e
feat(cdk-experimental/menu): explicitly specify the return when null …
andy9775 0fed70f
feat(cdk-experimental/menu): Clear up documentation/comments
andy9775 ba75cf5
feat(cdk-experimental/menu): Make cdkMenuOrientation comment more clear
andy9775 20ea413
feat(cdk-experimental/menu): Make orientation attribute public for co…
andy9775 dce973c
feat(cdk-experimental/menu): Remove unnecessary comment for role binding
andy9775 933edf9
feat(cdk-experimental/menu): Fix orientation attribute on host bindin…
andy9775 a07fe11
feat(cdk-experimental/menu): Refactor `orientation` property comment …
andy9775 a6dde62
feat(cdk-experimental/menu): Refactor event emitter types
andy9775 36b4b5e
feat(cdk-experimental/menu): Remove documentation to be added once fe…
andy9775 5d22b6b
feat(cdk-experimental/menu): Rename opensMenu method
andy9775 740217d
feat(cdk-experimental/menu): Use getter function not property for
andy9775 c2c7146
feat(cdk-experimental/menu): refactor MenuGroup doc for clarity
andy9775 633b573
feat(cdk-experimental/menu): add @jelbourn to CODEOWNERS for cdk-expe…
andy9775 559adf6
feat(cdk-experimental/menu): coerce MenuItem checked state to boolean
andy9775 2c9b997
feat(cdk-experimental/menu): nit: rename val to value
andy9775 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
CDK_EXPERIMENTAL_ENTRYPOINTS = [ | ||
"column-resize", | ||
"dialog", | ||
"menu", | ||
"popover-edit", | ||
"scrolling", | ||
] | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
load("//tools:defaults.bzl", "ng_module") | ||
|
||
package(default_visibility = ["//visibility:public"]) | ||
|
||
ng_module( | ||
name = "menu", | ||
srcs = glob( | ||
["**/*.ts"], | ||
exclude = ["**/*.spec.ts"], | ||
), | ||
module_name = "@angular/cdk-experimental/menu", | ||
deps = [ | ||
"@npm//@angular/core", | ||
"@npm//rxjs", | ||
], | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
export * from './public-api'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {Directive, Input} from '@angular/core'; | ||
|
||
/** | ||
* Directive applied to an element which configures it as a MenuBar by setting the appropriate | ||
* role, aria attributes, and accessable keyboard and mouse handling logic. The component that | ||
* this directive is applied to should contain components marked with CdkMenuItem. | ||
* | ||
*/ | ||
@Directive({ | ||
selector: '[cdkMenuBar]', | ||
exportAs: 'cdkMenuBar', | ||
mmalerba marked this conversation as resolved.
Show resolved
Hide resolved
|
||
host: { | ||
'role': 'menubar', | ||
'[attr.aria-orientation]': 'orientation', | ||
}, | ||
}) | ||
export class CdkMenuBar { | ||
/** | ||
* Sets the aria-orientation attribute and determines where sub-menus will be opened. | ||
* Does not affect styling/layout. | ||
*/ | ||
@Input('cdkMenuBarOrientation') orientation: 'horizontal' | 'vertical' = 'horizontal'; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {Directive, Output, OnDestroy} from '@angular/core'; | ||
import {Subject} from 'rxjs'; | ||
import {CdkMenuItem} from './menu-item'; | ||
|
||
/** | ||
* Directive which provides grouping logic for CdkMenuItem components marked with role | ||
* menuitemradio. | ||
* Siblings within the element are part of the same RadioGroup and behave as such. | ||
andy9775 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
@Directive({ | ||
selector: '[cdkMenuGroup]', | ||
exportAs: 'cdkMenuGroup', | ||
host: { | ||
'role': 'group', | ||
}, | ||
}) | ||
export class CdkMenuGroup implements OnDestroy { | ||
/** Emits the element when checkbox or radiobutton state changed */ | ||
@Output() change: Subject<CdkMenuItem> = new Subject(); | ||
andy9775 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** Cleanup event emitters */ | ||
ngOnDestroy() { | ||
this.change.complete(); | ||
andy9775 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {Directive, Output, Input, OnDestroy} from '@angular/core'; | ||
import {Subject} from 'rxjs'; | ||
import {CdkMenuPanel} from './menu-panel'; | ||
|
||
/** | ||
* Directive which provides behavior for an element which when clicked: | ||
* If located in a CdkMenuBar: | ||
* - opens up an attached submenu | ||
* | ||
* If located in a CdkMenu/CdkMenuGroup, one of: | ||
* - executes the user defined click handler | ||
* - toggles its checkbox state | ||
* - toggles its radio button state (in relation to siblings) | ||
* | ||
* If it's in a CdkMenu and it triggers a sub-menu, hovering over the | ||
* CdkMenuItem will open the submenu. | ||
* | ||
*/ | ||
@Directive({ | ||
selector: '[cdkMenuItem], [cdkMenuTriggerFor]', | ||
exportAs: 'cdkMenuItem', | ||
host: { | ||
'type': 'button', | ||
'[attr.role]': 'role', | ||
'[attr.aria-checked]': '_ariaChecked', | ||
}, | ||
}) | ||
export class CdkMenuItem implements OnDestroy { | ||
/** Template reference variable to the menu this trigger opens */ | ||
@Input('cdkMenuTriggerFor') _menuPanel: CdkMenuPanel; | ||
|
||
/** ARIA role for the menu item. */ | ||
@Input() role: 'menuitem' | 'menuitemradio' | 'menuitemcheckbox' = 'menuitem'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at this in code, I would probably lean towards having separate classes for
|
||
|
||
/** Whether the checkbox or radiobutton is checked */ | ||
@Input() checked: boolean; | ||
andy9775 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** Emits when the attached submenu is opened */ | ||
@Output() opened: Subject<void> = new Subject(); | ||
|
||
/** get the aria-checked value only if element is `menuitemradio` or `menuitemcheckbox` */ | ||
get _ariaChecked(): boolean | null { | ||
andy9775 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (this.role === 'menuitem') { | ||
return null; | ||
} | ||
return this.checked; | ||
} | ||
|
||
/** Whether the menu item opens a menu */ | ||
opensMenu() { | ||
andy9775 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return !!this._menuPanel; | ||
} | ||
|
||
/** Cleanup event emitters */ | ||
ngOnDestroy() { | ||
this.opened.complete(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {NgModule} from '@angular/core'; | ||
import {CdkMenu} from './menu'; | ||
import {CdkMenuBar} from './menu-bar'; | ||
import {CdkMenuPanel} from './menu-panel'; | ||
import {CdkMenuItem} from './menu-item'; | ||
import {CdkMenuGroup} from './menu-group'; | ||
|
||
const EXPORTED_DECLARATIONS = [CdkMenuBar, CdkMenu, CdkMenuPanel, CdkMenuItem, CdkMenuGroup]; | ||
@NgModule({ | ||
exports: EXPORTED_DECLARATIONS, | ||
declarations: EXPORTED_DECLARATIONS, | ||
}) | ||
export class CdkMenuModule {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {Directive} from '@angular/core'; | ||
import {CdkMenu} from './menu'; | ||
|
||
/** | ||
andy9775 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* Directive applied to an ng-template which wraps a CdkMenu and provides a reference to the | ||
* child element it wraps which allows for opening of the CdkMenu in an overlay. | ||
*/ | ||
@Directive({selector: 'ng-template[cdkMenuPanel]', exportAs: 'cdkMenuPanel'}) | ||
export class CdkMenuPanel { | ||
/** Reference to the child menu component */ | ||
_menu: CdkMenu; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
**Warning: this component is still experimental. It may have bugs and the API may change at any | ||
andy9775 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
time** | ||
|
||
# Menu | ||
|
||
The CDK's `MenuModule` provides a set of directives which allow developers to build custom Menus and | ||
MenuBars according the the [MenuBar design pattern](https://www.w3.org/TR/wai-aria-practices-1.1/#menu). | ||
|
||
## Example | ||
|
||
```html | ||
<ul cdkMenuBar> | ||
<li role="none"><button id="file_button" [cdkMenuTriggerFor]="file">File</button></li> | ||
<li role="none"><button id="edit_button" [cdkMenuTriggerFor]="edit">Edit</button></li> | ||
</ul> | ||
|
||
<ng-template cdkMenuPanel #file="cdkMenuPanel"> | ||
<ul cdkMenu id="file_menu"> | ||
<li role="none"><button id="share_button" cdkMenuItem>Share</button></li> | ||
<li role="none"><button id="open_button" cdkMenuItem>Open</button></li> | ||
<li role="none"><button id="rename_button" cdkMenuItem>Rename</button></li> | ||
<li role="none"><button id="print_button" cdkMenuItem>Print</button></li> | ||
</ul> | ||
</ng-template> | ||
|
||
<ng-template cdkMenuPanel #edit="cdkMenuPanel"> | ||
<ul cdkMenu id="edit_menu"> | ||
<li role="none"><button id="undo_button" cdkMenuItem>Undo</button></li> | ||
<li role="none"><button id="redo_button" cdkMenuItem>Redo</button></li> | ||
<li role="none"><button id="cut_button" cdkMenuItem>Cut</button></li> | ||
<li role="none"><button id="copy_button" cdkMenuItem>Copy</button></li> | ||
<li role="none"><button id="paste_button" cdkMenuItem>Paste</button></li> | ||
</ul> | ||
</ng-template> | ||
``` | ||
|
||
## Directives | ||
|
||
### cdkMenuBar | ||
|
||
`cdkMenuBar` should be applied to one root MenuBar component which contains a set of `cdkMenuItem` | ||
components. The directive should be applied to a unordered list component. Note that the component is | ||
always visible and is the main interaction point for the user. | ||
|
||
### cdkMenu | ||
|
||
`cdkMenu` is applied to the sub-menu component(s) which should be opened by an associated `cdkMenuItem`. | ||
`cdkMenu` components should not be nested and they should contain `cdkMenuItem` components or | ||
`cdkMenuGroup` components. | ||
|
||
### cdkMenuGroup | ||
|
||
`cdkMenuGroup` is used to logically group `cdkMenuItem` components when used with MenuItems which are | ||
a menuitemradio. | ||
|
||
`cdkMenuItem` components marked as `menuitemradio` inside of a `cdkMenuGroup` can only have a single | ||
active item and follow the RadioButton and RadioGroup standard pattern. | ||
|
||
### cdkMenuItem | ||
|
||
`cdkMenuItem` is applied to a component and performs one of the following actions based on the set role: | ||
|
||
- If menuitem: | ||
- triggers a submenu, or | ||
- performs some developer provided action | ||
- If menuitemcheckbox | ||
- can be toggled on/off and does not open a submenu | ||
- If menuitemradio | ||
- connected to sibling menuitemradio buttons (group) and does not open a submenu | ||
|
||
Further note that menuitemradio and menuitemcheckbox items may be grouped inside of either a `cdkMenu` | ||
or `cdkMenuGroup` as both directives logically group their children. | ||
|
||
### cdkMenuPanel | ||
|
||
`cdkMenuPanel` is to be applied to an `ng-template` component. It is used to reference the component it wraps (should contain a single `cdkMenu`) and opens it in an overlay. | ||
|
||
`cdkMenuPanel` is a top level element and should not be nested within any of the other directives mentioned here. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {Directive, Input, Output, OnDestroy} from '@angular/core'; | ||
import {CdkMenuItem} from './menu-item'; | ||
import {Subject} from 'rxjs'; | ||
|
||
/** | ||
* Directive which configures the element as a Menu which should contain child elements marked as | ||
* CdkMenuItem or CdkMenuGroup. Sets the appropriate role and aria-attributes for a menu and | ||
* contains accessable keyboard and mouse handling logic. | ||
* | ||
* It also acts as a RadioGroup for elements marked with role `menuitemradio`. | ||
*/ | ||
@Directive({ | ||
selector: '[cdkMenu]', | ||
exportAs: 'cdkMenu', | ||
host: { | ||
'role': 'menubar', | ||
'[attr.aria-orientation]': 'orientation', | ||
}, | ||
}) | ||
export class CdkMenu implements OnDestroy { | ||
/** | ||
* Sets the aria-orientation attribute and determines where sub-menus will be opened. | ||
* Does not affect styling/layout. | ||
*/ | ||
@Input('cdkMenuOrientation') orientation: 'horizontal' | 'vertical' = 'vertical'; | ||
|
||
/** Event emitted when the menu is closed. */ | ||
@Output() readonly closed: Subject<void | 'click' | 'tab' | 'escape'> = new Subject(); | ||
|
||
/** Emits the activated element when checkbox or radiobutton state changed */ | ||
@Output() change: Subject<CdkMenuItem>; | ||
|
||
/** Cleanup event emitters */ | ||
ngOnDestroy() { | ||
this.closed.complete(); | ||
this.change.complete(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
export * from './menu-module'; | ||
export * from './menu-bar'; | ||
export * from './menu'; | ||
export * from './menu-item'; | ||
export * from './menu-panel'; | ||
export * from './menu-group'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.