Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

Vertical tabs #1004

Merged
merged 107 commits into from
Sep 13, 2017
Merged

Vertical tabs #1004

merged 107 commits into from
Sep 13, 2017

Conversation

Blackbaud-AdamHickey
Copy link
Contributor

Adding vertical tabs to skyux 2 for issue #573

To reduce complexity I chose to create a separate vertical-tabs component instead of adding a vertical tab option on the existing tabs component. I can change this if necessary.

I am doing some DOM manipulation via a shared service to get the tab content to appear to the right. I'm open to a better way if possible.

@@ -14,6 +14,35 @@

</sky-demo-page-properties>

<sky-demo-page-properties sectionHeading="Vertical tabset properties">

Choose a reason for hiding this comment

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

These can probably be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, there is a difference between properties on the whole tabset and properties on the individual tabs. Is there a different term I should use?

Choose a reason for hiding this comment

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

Why do we need to document the vertical tabs properties on the "standard" tabs page (since vertical tabs has its own page now)? Are these properties also used here? Sorry, I might be misunderstanding...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, that's totally right I didn't realize I left this on the tabs documentation page. I thought you were commenting on the Vertal tabset properties vs Vertabl tab properties. I'll remove the changes to the tabs docs page.

public chevronClick() {
this.direction = this.direction === 'up' ? 'down' : 'up';
this.directionChange.emit(this.direction);
if (!this.disabled) {

Choose a reason for hiding this comment

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

The chevron component uses a native button element, which respects the disabled attribute, so I don't believe there's a reason to add conditions for tab index, etc. since the browser will turn those features off by default.

Unless I'm missing something critical, you can simply:

chevron.component.ts

@Input()
public disabled = false;

chevron.component.html

<button
  type="button"
  class="sky-chevron"
  [ngClass]="['sky-chevron-' + direction]"
  (click)="$event.stopPropagation();chevronClick()"
  [attr.aria-label]="(direction === 'down' ? 'chevron_expand' : 'chevron_collapse') | skyResources"
  [disabled]="disabled">
  <i class="sky-chevron-part sky-chevron-left"></i>
  <i class="sky-chevron-part sky-chevron-right"></i>
</button>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I add the tabindex because I don't want it to be tabbable even if it isn't disabled. In my case the tab group is tabbable but I don't want both the tab group and the button to be tabbable. I should add the [disabled] attribute to the button though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess I could go the other way and make the chevron tabbable and not the group div. I was just copying how it was done in skyux 1.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I checked and that is how it is done in the Tile component. I'll copy that instead of skyux 1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Using style of tiles in skyux 2 by making the chevron tabbable.

Choose a reason for hiding this comment

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

Awesome! Works great.

I removed the if (!this.disabled) { condition and it still worked as expected. Not sure if that's needed...

[ngClass]="{
'sky-vertical-tab-active': active,
'sky-no-outline': !outline,
'sky-outline': outline,

Choose a reason for hiding this comment

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

Preferably, the component should not know about the HTML's styles (i.e., outline). If the tab was an anchor element, it could be styled according to its native :focus attribute, and you wouldn't have to worry about keeping track of the outline boolean, or if the tab has focus.

.sky-vertical-tab:focus { // outline styles here }

Let me know if I'm missing something here, in the implementation!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. I removed the outline logic and changed it to a div.

</span>
</div>
<div #tabContentWrapper>
<div [ngClass]="{'sky-vertical-tab-hidden': !active, 'sky-vertical-tab-visible': active }">

Choose a reason for hiding this comment

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

Unsure why you need two classes for the visibility? Either it's visible by default, and hidden with a class, or vice versa?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was using that second class to grab the visible tabs in my unit tests. Should I use a different selector instead. Like id="verticalTab" without the hidden class?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. I removed the second class and added an id I could use with a css selector.


<div #tabContentWrapper>
<div
id="verticalTab"

Choose a reason for hiding this comment

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

I know you need to target this somehow in your unit tests, but I'd make the argument that it's not a good idea to use IDs in component templates because there could potentially be more than one on a given page.

Instead, you could add a default class to this div and reference that in your unit test:

<div
  class="sky-vertical-tab-content-pane"
  [ngClass]="{ 'sky-vertical-tab-hidden': !active }">
  <ng-content></ng-content>
</div>
el.querySelectorAll('.sky-vertical-tab-content-pane:not(.sky-vertical-tab-hidden)')

'sky-vertical-tab-active': active,
'sky-vertical-tab-disabled': disabled
}"
(click)="activateTabFromClick()"

Choose a reason for hiding this comment

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

You can probably do away with this method and simply call activateTab() again?


.sky-vertical-tab {
cursor: pointer;
padding: $sky-padding-3_4 0 $sky-padding-3_4 $sky-padding;

Choose a reason for hiding this comment

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

Nice! I like the use of SCSS variables, here.

>
<ng-content></ng-content>
</div>
</div>

Choose a reason for hiding this comment

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

Do you mind making the classnames a bit more specific?

vertical-tabset-group.component.html
.sky-tab-group-container --> .sky-vertical-tabset-group
.sky-tab-group-header --> .sky-vertical-tabset-group-header
.sky-tab-chevron --> .sky-vertical-tabset-group-header-chevron
.sky-tab-group-content --> .sky-vertical-tabset-group-content

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

{{ showTabsText }}
</button>
</div>
</div>

Choose a reason for hiding this comment

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

Same here, please:

vertical-tabset.component.html

.sky-vertical-tabset-container --> .sky-vertical-tabset
.sky-vertical-tabset-show-tabs --> .sky-vertical-tabset-show-tabs-btn

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@Blackbaud-SteveBrush
Copy link
Member

@Blackbaud-AdamHickey This is very clean; I especially liked your component classes.

@Blackbaud-ToddRoberts: I'm assuming you've approved the overall styles for the vertical tabs (note the addition of the (7) "counter" in one of the tabs)?

screen shot 2017-09-12 at 2 36 17 pm

@Blackbaud-ToddRoberts
Copy link
Contributor

Yup UI is good to go. The counter is good since it copies sectioned forms in UX1.

Copy link
Member

@Blackbaud-SteveBrush Blackbaud-SteveBrush left a comment

Choose a reason for hiding this comment

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

This is good stuff! The files are clean and easy to read, and the feature works great with a mouse and keyboard.

@Blackbaud-AdamHickey Blackbaud-AdamHickey merged commit 5631ec0 into master Sep 13, 2017
Copy link
Contributor

@blackbaud-johnly blackbaud-johnly left a comment

Choose a reason for hiding this comment

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

Providing feedback on the docs. I'm more than happy to implement the changes if someone confirms that my suggested changes are good and responds to the questions.

@@ -0,0 +1,78 @@
<sky-demo-page title="Vertical tabs">
Copy link
Contributor

Choose a reason for hiding this comment

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

title should be pageTitle

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok

propertyName="showTabsText"
isOptional="true"
>
Specifies the text to use for the show tabs button in mobile.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd tweak the wording here to "Specifies the text to display on the show tabs button on mobile devices."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah that is better.


<sky-demo-page-properties sectionHeading="Vertical tab properties">
<sky-demo-page-property
propertyName="active"
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the property names from this point on start with "[" and end with "]"? The properties are in these brackets in the code sample, where as the showTabsText property is not. So should we include the brackets in the name? Or is there some other way that developers should know which properties need brackets and which don't?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In angular, removing the brackets indicates a string literal for the input value. If the brackets are added then it uses object binding and looks for a property on the component with that name.

[input]="propertyNameOnComponent"
input="stringLiteral"

That is angular behavior and I don't think we have to document that.

propertyName="active"
isOptional="true"
>
Indicates whether or not the tab is active on load
Copy link
Contributor

Choose a reason for hiding this comment

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

Delete "or not" and end with a period. ... I'd also change "on load" to "when the tabset loads."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah agree.

<sky-demo-page-property
propertyName="tabHeading"
>
The text of the button that selects the tab.
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems weird to me. I see that the wording here is consistent with the wording for the corresponding property on the tabs module, but referring to this as "the button that selects the tab" seems weird. I mean, in help text, we usually refer to that as the tab. And in the next property, we refer to this as "the tab header." Similarly, in the groupHeading description, we refer to "the collapsible group of tabs," not "the collapsible group of buttons that select tabs." ... All of which is just a long way to ask, can we just say something like "The text to display on the tab." or "Specifies the tab header."? (I prefer the latter. ... Also, if we change this, I can go make the same edit to the corresponding property on the tabs module.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It definitely doesn't make sense on the vertical tabs to say button, but on the normal tab component, it actually creates buttons that are used to select the tab content.

I don't know how we feel about exposing implementation details like that in our docs. I would lean towards making your suggested change in both areas.

<sky-demo-page-property
propertyName="groupHeading"
>
Specifies the text to use in the heading of the collapsible group of tabs.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd change "text to use in the heading of" to "header for."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah.

propertyName="disabled"
isOptional="true"
>
Boolean value that can be set to disabled expanding and collapsing a collapsible group.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd change "Boolean value that can be set" to "Indicates whether" and change "disabled" to "disable."

I'd also change "expanding and collapsing" to "the ability to open and collapse." (I assume "expand" should be "open" for consistency since the next property is open, not expand.)

Change "a" before "collapsible" to "the."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah.

propertyName="open"
isOptional="true"
>
Boolean value indicating if the collapsible group is open.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd change "Boolean value indicating if" to "Indicates whether."

Also, should this have something like "when the tabset loads" at the end?

Copy link
Contributor Author

@Blackbaud-AdamHickey Blackbaud-AdamHickey Sep 13, 2017

Choose a reason for hiding this comment

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

Yeah. Although I'm not sure we need "when the tabset loads". The boolean value will update each time the group is expanded/collapsed.

<sky-demo-page-property
propertyName="activeChange"
>
Fires when the active tab changes. Emits the index of the active tab.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the second sentence end with something like "that is based on its position when it loads"? If accurate, would that be useful? (Not really sure if that's accurate, but assuming so based on the tabIndex property in the tabs module and the fact that there isn't a way here to set the index.)

Copy link
Contributor Author

@Blackbaud-AdamHickey Blackbaud-AdamHickey Sep 13, 2017

Choose a reason for hiding this comment

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

Yeah, it is based on how it loads starting with 0.

<group>
  <tab1 index = 0>
  <tab2 index = 1>
</group>
<group>
   <tab3 index = 2>
</group>

isOpen: false,
isDisabled: false,
subTabs: [
{ tabHeading: 'Group 1 - Tab 1', content: 'Group 1 - Tab 1 Content'},
Copy link
Contributor

Choose a reason for hiding this comment

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

Very minor, but I'd recommend replacing the hyphens here with long dashes. So "—" instead of "-"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok

@Blackbaud-AdamHickey Blackbaud-AdamHickey deleted the vertical-tabs branch September 14, 2017 19:33
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants