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: Implement icon component #41

Merged
merged 9 commits into from
Aug 5, 2024
111 changes: 111 additions & 0 deletions packages/ember-test-app/app/components/f/icon.gts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import Component from '@glimmer/component';
import Icon from '@nrg-ui/ember/components/icon';
import FreestyleSection from 'ember-freestyle/components/freestyle-section';
import FreestyleUsage from 'ember-freestyle/components/freestyle/usage';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { fn } from '@ember/helper';

export default class extends Component {
colorOptions = [
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
];

backgroundColorOptions = [
'',
'primary-subtle',
'primary',
'secondary-subtle',
'secondary',
'success-subtle',
'success',
'danger-subtle',
'danger',
'warning-subtle',
'warning',
'info-subtle',
'info',
'light-subtle',
'light',
'dark-subtle',
'dark',
];
@tracked
class = '';

@tracked
type = 'bi-telephone';

@tracked
color = 'primary';

@tracked
circular = false;

@tracked
backgroundColor = undefined;

@action
update(key: string, value: unknown) {
if (key === 'circular' && value === false) {
this.backgroundColor = undefined;
}
this[key] = value;
}

<template>
<FreestyleSection @name="Icon" as |Section|>
<Section.subsection @name="Basics">
<FreestyleUsage>
<:example>
<Icon
@backgroundColor={{this.backgroundColor}}
@circular={{this.circular}}
@color={{this.color}}
@type={{this.type}}
/>
</:example>
<:api as |Args|>
<Args.String
@defaultValue="{{this.color}}-subtle"
@description="When circular is true, the background color will be determined if a value is passed here. Note that default of this value is the subtle version of the color used for icon color."
@name="backgroundColor"
@value={{this.backgroundColor}}
@options={{this.backgroundColorOptions}}
@onInput={{fn this.update "backgroundColor"}}
/>
<Args.Bool
@defaultValue={{false}}
@description="When true, the icon will render within a padded circle. Note that the default value is false."
@name="circular"
@value={{this.circular}}
@onInput={{fn this.update "circular"}}
/>
<Args.String
@description="The color of the icon."
@name="color"
@options={{this.colorOptions}}
@required={{true}}
@value={{this.color}}
@onInput={{fn this.update "color"}}
/>
<Args.String
@description="The bootstrap icon type. This is a class that is applied to the icon tag utilizing Bootstrap's icon library."
@name="type"
@required={{true}}
@value={{this.type}}
@onInput={{fn this.update "type"}}
/>
</:api>
</FreestyleUsage>
</Section.subsection>
</FreestyleSection>
</template>
}
1 change: 1 addition & 0 deletions packages/ember-test-app/app/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Router.map(function () {
this.route('faq');
this.route('components', function () {
this.route('button');
this.route('icon');
this.route('navbar');
});
this.route('helpers');
Expand Down
6 changes: 6 additions & 0 deletions packages/ember-test-app/app/templates/components.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
>
Button
</LinkTo>
<LinkTo
@route="components.icon"
class="list-group-item list-group-item-action"
>
Icon
</LinkTo>
<LinkTo
@route="components.navbar"
class="list-group-item list-group-item-action"
Expand Down
5 changes: 5 additions & 0 deletions packages/ember-test-app/app/templates/components/icon.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{page-title "Icon"}}

<div class="container mx-auto">
<F::Icon />
</div>
41 changes: 41 additions & 0 deletions packages/ember-test-app/tests/integration/components/icon-test.gts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { assert, module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import Icon from '@nrg-ui/ember/components/icon';

module('Integration | components | icon', function (hooks) {
setupRenderingTest(hooks);

test('icon renders without circular background', async function () {
await render(<template>
<Icon class="test" @type="icon" @color="primary" />
</template>);

assert.dom('.d-flex.test').exists('Icon renders passed attributes');
assert.notOk(
document.querySelector('.rounded-circle'),
'Icon does not have rounded-circle class when @circular is not passed',
);
assert
.dom('div div i')
.hasClass('icon', 'Type param renders icon correctly');
assert
.dom('div div i')
.hasClass('text-primary', 'Color param renders text color correctly');
});

test('icon renders with circular background', async function () {
await render(<template>
<Icon class="test" @type="icon" @color="warning" @circular={{true}} />
</template>);
assert
.dom('.test div')
.hasClass(
'rounded-circle',
'Icon has rounded-circle class when @circular is true',
);
assert
.dom('.test div')
.hasClass('bg-warning-subtle', 'Icon bubble has correct bg color passed');
});
});
1 change: 1 addition & 0 deletions packages/ember/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
"./components/card.js": "./dist/_app_/components/card.js",
"./components/footer.js": "./dist/_app_/components/footer.js",
"./components/header.js": "./dist/_app_/components/header.js",
"./components/icon.js": "./dist/_app_/components/icon.js",
"./components/loading-indicator.js": "./dist/_app_/components/loading-indicator.js",
"./components/mktg/card-container.js": "./dist/_app_/components/mktg/card-container.js",
"./components/mktg/card.js": "./dist/_app_/components/mktg/card.js",
Expand Down
64 changes: 64 additions & 0 deletions packages/ember/src/components/icon.gts
TSenter marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Component from '@glimmer/component';
import type { NrgIconValue } from '../';

declare type SubtleColorType =
| 'primary-subtle'
| 'secondary-subtle'
| 'success-subtle'
| 'danger-subtle'
| 'warning-subtle'
| 'info-subtle'
| 'light-subtle'
| 'dark-subtle';

declare type ColorType =
| 'primary'
| 'secondary'
| 'success'
| 'danger'
| 'warning'
| 'info'
| 'light'
| 'dark';

interface IconSignature {
Element: HTMLDivElement;
Args: {
type: NrgIconValue;
backgroundColor?: SubtleColorType | ColorType;
color: ColorType;
circular?: boolean;
};
}

export default class Icon extends Component<IconSignature> {
get color() {
return this.args.color || 'reset';
}

get backgroundColor() {
if (this.args.backgroundColor) {
return this.args.backgroundColor;
}
if (!this.args.color) {
return 'bg-transparent';
}
return `${this.args.color}-subtle`;
}

get classList() {
let classes = ['d-flex', 'justify-content-center', 'fs-2', 'm-2'];
if (this.args.circular) {
classes.push('rounded-circle', 'p-3', `bg-${this.backgroundColor}`);
}
return classes.join(' ');
}

<template>
<div class="d-flex" ...attributes>
<div class={{this.classList}}>
<i class="bi {{@type}} text-{{this.color}}" />
</div>
</div>
</template>
}
1 change: 1 addition & 0 deletions packages/ember/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export type Binding = {
valuePath: string;
};
export type Optional<T> = T | null;
export type { NrgIconValue } from './icon-types.d.ts';