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

Add icon widget #477

Closed
wants to merge 17 commits into from
Closed

Add icon widget #477

wants to merge 17 commits into from

Conversation

maier49
Copy link
Contributor

@maier49 maier49 commented Feb 16, 2018

Type: feature

The following has been addressed in the PR:

  • There is a related issue
  • All code matches the style guide
  • Unit or Functional tests are included in the PR

Description:

Resolves #463

import { w } from '@dojo/widget-core/d';

w(Icon, {
type: 'downIcon'
Copy link
Member

Choose a reason for hiding this comment

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

can you add aria usage to the example please

src/icon/icon.ts Outdated
}

constructor() {
super();
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 think you need this

src/icon/icon.ts Outdated
protected render(): DNode {
const {
aria = {},
type = 'downIcon'
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should have a default for type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should the property be required on the props then or just render without an icon type if it's not provided?

@codecov
Copy link

codecov bot commented Feb 16, 2018

Codecov Report

Merging #477 into master will increase coverage by 0.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #477      +/-   ##
==========================================
+ Coverage   97.34%   97.36%   +0.01%     
==========================================
  Files          31       32       +1     
  Lines        2414     2431      +17     
  Branches      629      630       +1     
==========================================
+ Hits         2350     2367      +17     
  Misses          9        9              
  Partials       55       55
Impacted Files Coverage Δ
src/text-input/index.ts 99.03% <ø> (ø) ⬆️
src/dialog/index.ts 98.61% <100%> (-0.04%) ⬇️
src/calendar/index.ts 99.49% <100%> (ø) ⬆️
src/button/index.ts 100% <100%> (ø) ⬆️
src/toolbar/index.ts 91.04% <100%> (ø) ⬆️
src/icon/index.ts 100% <100%> (ø)
src/select/index.ts 96.21% <100%> (ø) ⬆️
src/title-pane/index.ts 98.3% <100%> (ø) ⬆️
src/slide-pane/index.ts 89.28% <100%> (-0.16%) ⬇️
src/combobox/index.ts 97.65% <100%> (ø) ⬆️
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fcbb79c...29a1ad8. Read the comment docs.

Copy link
Contributor

@smhigley smhigley left a comment

Choose a reason for hiding this comment

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

Nice first widget addition!

src/icon/Icon.ts Outdated
export class IconBase<P extends IconProperties = IconProperties> extends ThemedBase<P, null> {
private _onClick (event: MouseEvent) {
event && event.stopPropagation();
this.properties.onClick && this.properties.onClick();
Copy link
Contributor

Choose a reason for hiding this comment

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

We shouldn't be providing an onClick event, since icons aren't interactive -- they're not buttons, nothing indicates they can be clicked, and they are neither focusable nor keyboard-operable. If someone wants an icon to do something, they need to wrap it in a button or link.

Copy link
Member

Choose a reason for hiding this comment

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

Good point, missed that :)

src/icon/Icon.ts Outdated
} = this.properties;

return v('i', {
...formatAriaProperties(aria),
Copy link
Contributor

Choose a reason for hiding this comment

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

It's good to include the aria props, but it might be worthwhile to also have an explicit property for hidden descriptive text, maybe like altText? If it's provided, we can leave off role="presentation" and include a visually hidden span with the text. If it's not provided, we can include role="presentation" and aria-hidden="true"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now it's always setting aria-hidden="true" on the icon itself (unless explicitly overridden), never setting role="presentation" on anything, and includes a visually hidden with altText if provided.

src/icon/Icon.ts Outdated
*/
export interface IconProperties extends ThemedProperties, CustomAriaProperties {
type: IconType;
altText?: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Yay! Could you just add it to typedoc and the customElement decorator?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added

src/icon/Icon.ts Outdated
const {
aria = {
hidden: 'true'
},
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we want to default to aria-hidden="true", because that will hide the alt text if provided. It should probably only be present if altText is missing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As we talked about, the label is a sibling of the icon so we can safely always hide the icon.

```

By default the icon will be rendered with `role="presentation"` and
`aria-hidden="true"`. Custom aria attributes can be specified to
Copy link
Contributor

Choose a reason for hiding this comment

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

Really quick word update to something like "The icon will be rendered with role="presentation" and
+aria-hidden="true" if altText is not provided"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated this, but with slightly different wording since we'll always have aria-hidden="true" regardless of whether altText is provided.

@@ -134,7 +127,7 @@ export class ButtonBase<P extends ButtonProperties = ButtonProperties> extends T
'aria-pressed': typeof pressed === 'boolean' ? pressed.toString() : null
}, [
...this.getContent(),
popup ? this.renderPopupIcon() : null
popup ? w(Icon, { extraClasses: { root: css.addon }, type: 'downIcon' }) : null
Copy link
Member

Choose a reason for hiding this comment

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

this won't work as extraClasses is not themeable. You'll likely need to wrap it in a span or a div and pass the css.addon class to that instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wrapped them in a span

@@ -1,12 +1,13 @@

Copy link
Member

Choose a reason for hiding this comment

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

why the new line?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Formatting failure. Removed these from all the files they were in.

role: 'presentation',
'aria-hidden': 'true'
})
w(Icon, { type: 'downIcon', extraClasses: { root: css.addon } })
Copy link
Member

Choose a reason for hiding this comment

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

same comment again re. wrapping the icon with something for the sake of css.addon

src/icon/Icon.ts Outdated
})
export class IconBase<P extends IconProperties = IconProperties> extends ThemedBase<P, null> {
protected renderAltText(altText?: string) {
return altText && v('span', { classes: [ baseCss.visuallyHidden ] }, [ altText ]);
Copy link
Member

Choose a reason for hiding this comment

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

could the altText not just be a title attribute on the i tag? @smhigley ??

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 think having a separate span is preferred.

src/icon/Icon.ts Outdated
}
}

export default class Icon extends IconBase<IconProperties> {}
Copy link
Member

Choose a reason for hiding this comment

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

just export default class Icon

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure I follow. Do you want me to get rid of the base class?

Copy link
Contributor

Choose a reason for hiding this comment

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

@tomdye I'm not entirely sure if this is what you meant, but this pattern was adopted because of typing weirdness around lack of type narrowing when providing the generic for properties.

src/icon/Icon.ts Outdated
*
* Properties that can be set on an Icon component
*
* @property type Icon type, e.g. downIcon, searchIcon, etc.
Copy link
Contributor

Choose a reason for hiding this comment

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

I promise this is the very last thing: could you add altText after this?

Copy link
Contributor

Choose a reason for hiding this comment

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

nevermind! My view was out of date :)

Copy link
Contributor

@smhigley smhigley left a comment

Choose a reason for hiding this comment

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

Just have the one comment for adding a description for altText for typedoc. Other than that, I'm good for you to merge this 👍

Copy link
Member

@tomdye tomdye left a comment

Choose a reason for hiding this comment

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

Looks good, just one question about the IconType.

@@ -375,13 +374,11 @@ export class CalendarBase<P extends CalendarProperties = CalendarProperties> ext
}

protected renderPagingButtonContent(type: Paging, labels: CalendarMessages): DNode[] {
const iconClass = type === Paging.next ? iconCss.rightIcon : iconCss.leftIcon;
const iconType = type === Paging.next ? 'rightIcon' : 'leftIcon';
Copy link
Member

Choose a reason for hiding this comment

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

could this be IconType.rightIcon ? Might be better using the exported type. There's a few instances like this within this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now IconType is just a type, so there is no IconType.rightIcon.

@tomdye
Copy link
Member

tomdye commented Feb 21, 2018

@maier49 this will require a change in @dojo/themes too as the icons filename has changed.

@tomdye tomdye mentioned this pull request Feb 21, 2018
3 tasks
@tomdye
Copy link
Member

tomdye commented Feb 21, 2018

@maier49 I raised dojo/themes#9 to go with this change.

@tomdye
Copy link
Member

tomdye commented Feb 27, 2018

@maier49 looks like this is failing CI right now

@maier49 maier49 force-pushed the icon-widget branch 2 times, most recently from 4c41b05 to 38143d3 Compare February 27, 2018 18:00

*Basic Example*
```typescript
import Icon from '@dojo/widgets/icon/index';
Copy link
Member

Choose a reason for hiding this comment

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

When people use our widgets in their own apps they don't need to use /index, this is just for our AMD test loaders sadly. I'm happy to let this go as it though and will update all readmes in a follow up PR

const altTextNode = this.renderAltText(altText);
const icon = this.renderIcon(type, aria);

return v('span', { classes: this.theme(css.root) }, [
Copy link
Member

Choose a reason for hiding this comment

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

Do you think this really needs a renderIcon method? I can't see anyone ever extending it, it's simply an icon.
As for renderAltText, I think that it should only be called if there is altText.

return v('span', { classes: this.theme(css.root) }, [
   v('i', {
      ...formatAriaProperties(aria),
      classes: this.theme([ css.icon, css[type] ])
   }),
   altText ? this.renderAltText(altText) : null
]);

url('./fonts/dojo2.ttf?fkcsox') format('truetype'),
url('./fonts/dojo2.woff?fkcsox') format('woff'),
url('./fonts/dojo2.svg?fkcsox#dojo2') format('svg');
url('../common/fonts/dojo2.ttf?fkcsox') format('truetype'),
Copy link
Member

Choose a reason for hiding this comment

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

I believe this path was correct before, the font files are in ./fonts

@tomdye tomdye mentioned this pull request Feb 28, 2018
3 tasks
@tomdye
Copy link
Member

tomdye commented Feb 28, 2018

Raised #494 to replace this PR

@tomdye tomdye closed this Feb 28, 2018
@dylans dylans added this to the 2018.02 milestone Feb 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants