Skip to content
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

feat(expansion-panel): initial version of expansion panel #4191

Merged
merged 1 commit into from
Jun 7, 2017

Conversation

josephperrott
Copy link
Member

For #3664 and #995

@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Apr 21, 2017
@jelbourn jelbourn changed the title feat(MdExpansionPanel): Create Expansion Panel feat(expansion-panel): initial version of expansion panel Apr 21, 2017
@@ -0,0 +1,6 @@
<ng-content select="md-summary"></ng-content>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one also needs to handle mat-summary.

@@ -0,0 +1,6 @@
<ng-content select="md-summary"></ng-content>
<div class="md-expansion-panel-body" [class.expanded]="expanded"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expanded class needs to be prefixed (e.g. mat-expanded).

<div class="md-expansion-panel-body" [class.expanded]="expanded"
[@bodyExpansion]="booleanToString(expanded)" [id]="getExpansionPanelId()">
<ng-content></ng-content>
<ng-content select="[md-action-row]"></ng-content>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also support the mat-prefix.

display: block;

&:not(:first-child) {
border-top: 1px solid rgba(0, 0, 0, 0.12);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The color here and on line 33 should come from the theme.

@include mat-elevation(2);
}

&[wide='true'] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this should be done through a class? Also it won't work if wide was used as a boolean attribute (e.g. <md-expansion-panel wide>.

return this.panelSet && this.panelSet.style === 'wide';
}
/** Whether the expansion panel is expanded. */
private _expanded: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be a good idea to add a default value to this one.

line-height: $md-summary-height;
padding: 0 24px;

.content {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class should be prefixed with mat- and not be nested.


&:focus,
&:hover {
background: rgb(238, 238, 238);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The color should be inside the theme. The same goes for [title], [description] etc.


&.expanded:focus,
&.expanded:hover, {
background: initial;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK initial doesn't work on IE.

'[attr.aria-expanded]': 'parentPanel.expanded',
'[class.mat-summary]': 'true',
'[class.expanded]': 'parentPanel.expanded',
'(click)': 'parentPanel.expanded = !parentPanel.expanded',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if these expressions were in a method inside the class, instead of inline.

crisbeto added a commit to crisbeto/material2 that referenced this pull request Apr 21, 2017
Throws a Stylelint error when using the `initial` value for a property. `initial` doesn't work in IE and is easy to work around by looking up the default value for the property.

Related to angular#4191 (comment).
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finished first pass, also agree w/ all of @crisbeto's comments.

@@ -0,0 +1,54 @@
<h1>Single Expansion Panel</h1>
<md-expansion-panel class="md-expansion-demo-width" #myPanel>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this to <md-details> (and update all surrounding text)? I know that the spec calls them "expansion panel", but I'd prefer to stick closer to the native API where possible

(e.g., the spec refers to "select" as "dropdown button" and to inputs as "text field")

box-sizing: content-box;
display: block;

&:not(:first-child) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.mat-expansion-panel could be the first child of an arbitrary div

}
}

div.md-expansion-panel-body {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is div part of this selector?

@Directive({
selector: 'md-expansion-panel-set, mat-expansion-panel-set',
host: {
'[class.mat-expansion-panel-set]': 'true',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use a static class here, e.g.:

host: {'class': 'mat-expansion-panel-set'},

So long as it's not a '[class]' binding (which will clobber other classes)

export const EXPANSION_PANEL_ANIMATION_TIMING = '225ms cubic-bezier(0.4,0.0,0.2,1)';

@Directive({
selector: 'md-expansion-panel-set, mat-expansion-panel-set',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A group of expansion panels is typically called an accordion. Accordions also have special a11y treatment on top of the standalone panel: https://www.w3.org/TR/wai-aria-practices-1.1/#accordion. It's possible that this maybe be a completely separate component that just shares some code with the expansion panel.

Maybe leave this out for now and add it in a follow-up?

})
export class MdExpansionPanelSet implements AfterContentInit, OnDestroy {
/** Whether the panel set should use flat styling. */
@Input('style') style: 'default' | 'flat' | 'wide' = 'default';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these different styles? I don't see anything about them in the spec. Is this something the user wouldn't be able to accomplish with css?

/** Whether the panel set should use flat styling. */
@Input('style') style: 'default' | 'flat' | 'wide' = 'default';
/** Whether the panel set should allow multiple open panels. */
@Input('multi') multi: boolean = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a boolean property that uses coerceBooleanProperty

templateUrl: './expansion-panel.html',
encapsulation: ViewEncapsulation.None,
host: {
'[class.mat-expansion-panel]': 'true',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing about 'class' here

/** Unique identifier for the expansion panel, to be used by aria attributes. */
private _expansionPanelId: number;
/** Event emitted for each expanded state change. */
@Output('expandChange') expandChange = new EventEmitter<boolean>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the name when it's the same as the property

/** Event emitted for each expanded state change. */
@Output('expandChange') expandChange = new EventEmitter<boolean>();
/** Event emitted every time the expansion panel is closed. */
@Output('close') close = new EventEmitter<null>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's no event object you should do EventEmitter<void>

@josephperrott josephperrott force-pushed the expansion-panel branch 6 times, most recently from 123a404 to 112f8f8 Compare April 29, 2017 00:36
@josephperrott josephperrott force-pushed the expansion-panel branch 5 times, most recently from aeff3d5 to 1638087 Compare May 2, 2017 16:33
@josephperrott josephperrott force-pushed the expansion-panel branch 7 times, most recently from b658745 to 50ff89e Compare May 9, 2017 01:56
@josephperrott josephperrott force-pushed the expansion-panel branch 3 times, most recently from 7edcfcf to 3ff00ca Compare May 10, 2017 23:55
@josephperrott josephperrott force-pushed the expansion-panel branch 2 times, most recently from 23356a0 to 25de2f2 Compare May 24, 2017 03:57
@@ -0,0 +1,41 @@
import {NgModule, ModuleWithProviders} from '@angular/core';
import {CommonModule} from '@angular/common';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this BrowserAnimationsModule import a problem?
I merged this PR into master and did a build, but my App now has this error:

Error: BrowserModule has already been loaded.

I modified publish-build-artifacts.sh to deploy to my repo and ran it.
See angular/material-builds@master...arlowhite:master
Load diff for material.js
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
You can see that this import has been added.

ng version

@angular/cli: 1.0.4
node: 6.9.1
os: linux x64
@angular/common: 4.1.3
@angular/material: 2.0.0-beta.5-25de2f2

Copy link

@arlowhite arlowhite May 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed. Removing the import fixes the load error.
This build works: arlowhite/material2-builds@63ae5f5
Original does not: arlowhite/material2-builds@54a809f

EDIT: I confused myself earlier by moving my BrowserAnimationsModule import to my app's SharedModule instead of CoreModule, which causes the error in both builds.

@arlowhite
Copy link

The arrow icon is reversed from what the Material Guideline recommends:
https://material.io/guidelines/components/expansion-panels.html#expansion-panels-behavior
Arrow should point down when collapsed.

@josephperrott josephperrott force-pushed the expansion-panel branch 5 times, most recently from 6df441b to 34ce9c0 Compare May 31, 2017 23:43
@csvn csvn mentioned this pull request Jun 2, 2017
@josephperrott josephperrott force-pushed the expansion-panel branch 2 times, most recently from e89cecc to f8dbdc8 Compare June 2, 2017 20:50
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last handful of comments from me

import {Subject} from 'rxjs/Subject';
import 'rxjs/add/operator/takeUntil';
import {CdkAccordion, CdkAccordionDisplayMode} from './accordion';
import {CdkAccordionItem} from './accordion-item';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of unused imports

@Input() hideToggle: boolean = true;

/** The expansion panel style. */
@Input() panelStyle: string = 'default';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be unused now

// Only emit events and update the internal value if the value changes.
if (this._expanded !== expanded) {
this._expanded = expanded;
if (expanded) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(expanded ? this.opened : this.closed).emit();

import {Subscription} from 'rxjs/Subscription';
import {Subject} from 'rxjs/Subject';
import 'rxjs/add/operator/takeUntil';
import {CdkAccordionItem} from './accordion-item';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of unused imports

}

/** Toggles the expanded state of the panel. */
toggle(): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should have public methods for open and close as well

}
private _expanded: boolean;

constructor(@Optional() @Host() public accordion: CdkAccordion,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is @Host what you want here? Shouldn't you just get what you want from CdkAccordion by itself?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought was if you had a CdkAccordion inside of another CdkAccordion that you wanted to be sure you got the correct CdkAccordion, so we only look at the host component. However now that you point it out I see how flawed that logic is as it will get the first one it finds on its way up the tree.

set hideToggle(show: boolean) { this._hideToggle = coerceBooleanProperty(show); }
private _hideToggle: boolean = false;

/** Whether the panel set should use flat styling. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment should be updated (still written as a boolean). Should explain the difference between the modes.

* Directive whose purpose is to manage the expanded state of CdkAccordionItem children.
*/
@Directive({
selector: '[cdk-accordion]',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this one an attribute instead of an element?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we should make a separate <md-accordion> that is probably just

@Directive({ selector: 'md-accordion'})
export class MdAccordion extends CdkAccordion { }

Just so users don't have to mix md- and cdk-

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea for it being an attribute rather than an element is because it is simply a containing item for the children who control there own spacing and styling. Since there is nothing in this directive that affects the document flow, it seemed to make sense that you could just mark another element as the containing element for the children.

switch (event.keyCode) {
// Toggle for space and enter keys.
case SPACE:
case ENTER:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want to preventDefault on these (space will scroll and enter may submit a form)

<div class="mat-expansion-panel-body">
<ng-content></ng-content>
</div>
<ng-content select="[mat-action-row], [md-action-row]"></ng-content>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should use an element selector (e.g. <md-action-row>)

@josephperrott josephperrott force-pushed the expansion-panel branch 3 times, most recently from df68323 to e740a4e Compare June 3, 2017 18:01
@josephperrott
Copy link
Member Author

@jelbourn Comments addressed ready for a look

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jelbourn jelbourn added pr: lgtm action: merge The PR is ready for merge by the caretaker labels Jun 5, 2017
@jelbourn
Copy link
Member

jelbourn commented Jun 5, 2017

@andrewseguin this one will need new build rules when syncing

@josephperrott josephperrott force-pushed the expansion-panel branch 2 times, most recently from ca99138 to 5ea821f Compare June 7, 2017 22:57
@andrewseguin andrewseguin merged commit cac7610 into angular:master Jun 7, 2017
@otienoanyango
Copy link

Really excited about this. Great job guys!

@k-krupka
Copy link

k-krupka commented Jul 4, 2017

Even in beta, awesome.
When sb does something good, they should be told about this. Nice work then!

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 6, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants