-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(breadcrumb): add new
bq-breadcrumb
component (#266)
- Loading branch information
1 parent
c015bf0
commit 07d4da5
Showing
12 changed files
with
803 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
48 changes: 48 additions & 0 deletions
48
packages/bee-q/src/components/breadcrumb-item/__tests__/bq-breadcrumb-item.e2e.ts
This file contains 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,48 @@ | ||
import { newE2EPage } from '@stencil/core/testing'; | ||
|
||
describe('bq-breadcrumb-item', () => { | ||
it('should render', async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent('<bq-breadcrumb-item></bq-breadcrumb-item>'); | ||
|
||
const element = await page.find('bq-breadcrumb-item'); | ||
|
||
expect(element).toHaveClass('hydrated'); | ||
}); | ||
|
||
it('should have shadow root', async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent('<bq-breadcrumb-item></bq-breadcrumb-item>'); | ||
|
||
const element = await page.find('bq-breadcrumb-item'); | ||
|
||
expect(element.shadowRoot).not.toBeNull(); | ||
}); | ||
|
||
it('should display text', async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent('<bq-breadcrumb-item>Home</bq-breadcrumb-item>'); | ||
|
||
const element = await page.find('bq-breadcrumb-item'); | ||
|
||
expect(element).toEqualText('Home'); | ||
}); | ||
|
||
it('should render `button` tag', async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent('<bq-breadcrumb-item>Home</bq-breadcrumb-item>'); | ||
|
||
const element = await page.find('bq-breadcrumb-item >>> .breadcrumb-item'); | ||
|
||
expect(element.tagName.toLocaleLowerCase()).toBe('button'); | ||
}); | ||
|
||
it('should render `a` tag', async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent('<bq-breadcrumb-item href="https://example.com/">Home</bq-breadcrumb-item>'); | ||
|
||
const element = await page.find('bq-breadcrumb-item >>> .breadcrumb-item'); | ||
|
||
expect(element.tagName.toLocaleLowerCase()).toBe('a'); | ||
}); | ||
}); |
139 changes: 139 additions & 0 deletions
139
packages/bee-q/src/components/breadcrumb-item/bq-breadcrumb-item.tsx
This file contains 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,139 @@ | ||
import { h, Component, Prop, Element, Event, EventEmitter } from '@stencil/core'; | ||
|
||
import { isDefined } from '../../shared/utils'; | ||
|
||
/** | ||
* @part base - The component wrapper container | ||
* @part base - The breadcrumb item wrapper (`button` or `a`) | ||
* @part content - The `span` tag that loads the content item | ||
* @part separator - The `span` tag that loads the separator | ||
*/ | ||
@Component({ | ||
tag: 'bq-breadcrumb-item', | ||
styleUrl: './scss/bq-breadcrumb-item.scss', | ||
shadow: true, | ||
}) | ||
export class BqBreadcrumbItem { | ||
// Own Properties | ||
// ==================== | ||
|
||
// Reference to host HTML element | ||
// =================================== | ||
|
||
@Element() el!: HTMLBqBreadcrumbItemElement; | ||
|
||
// State() variables | ||
// Inlined decorator, alphabetical order | ||
// ======================================= | ||
|
||
// Public Property API | ||
// ======================== | ||
|
||
/** | ||
* The aria-label that corresponds to the full title of the destination page. | ||
* This won't be shown in the page, but it will be used by screen readers and other assistive devices. | ||
*/ | ||
@Prop() ariaLabel: string; | ||
|
||
/** If true, the item is the last element inside breadcrumb */ | ||
@Prop() isLastItem: boolean = false; | ||
|
||
/** If set, the breadcrumb item will be rendered as an `<a>` with this `href`, otherwise, a `<button>` will be rendered. */ | ||
@Prop({ reflect: true }) href: string; | ||
|
||
/** Where to display the link in the browser context. Relevant only if `href` is set. */ | ||
@Prop({ reflect: true }) target: '_blank' | '_parent' | '_self' | '_top'; | ||
|
||
/** Where to display the link in the browser context. Relevant only if `href` is set. */ | ||
@Prop({ reflect: true }) rel: string = 'noreferrer noopener'; | ||
|
||
// Prop lifecycle events | ||
// ======================= | ||
|
||
// Events section | ||
// Requires JSDocs for public API documentation | ||
// ============================================== | ||
|
||
/** Handler to be called when item loses focus */ | ||
@Event() bqBlur: EventEmitter<HTMLBqBreadcrumbItemElement>; | ||
|
||
/** Handler to be called when item is focused */ | ||
@Event() bqFocus: EventEmitter<HTMLBqBreadcrumbItemElement>; | ||
|
||
/** Handler to be called when item is clicked */ | ||
@Event() bqClick: EventEmitter<HTMLBqBreadcrumbItemElement>; | ||
|
||
// Component lifecycle events | ||
// Ordered by their natural call order | ||
// ===================================== | ||
|
||
// Listeners | ||
// ============== | ||
|
||
// Public methods API | ||
// These methods are exposed on the host element. | ||
// Always use two lines. | ||
// Public Methods must be async. | ||
// Requires JSDocs for public API documentation. | ||
// =============================================== | ||
|
||
// Local methods | ||
// Internal business logic. | ||
// These methods cannot be called from the host element. | ||
// ======================================================= | ||
|
||
private onBlur = () => { | ||
this.bqBlur.emit(this.el); | ||
}; | ||
|
||
private onFocus = () => { | ||
this.bqFocus.emit(this.el); | ||
}; | ||
|
||
private onClick = () => { | ||
this.bqClick.emit(this.el); | ||
}; | ||
|
||
// render() function | ||
// Always the last one in the class. | ||
// =================================== | ||
|
||
render() { | ||
const isLink = isDefined(this.href); | ||
const TagElem = isLink ? 'a' : 'button'; | ||
|
||
return ( | ||
<div class="flex items-center" aria-label={this.ariaLabel} part="base"> | ||
<TagElem | ||
class="breadcrumb-item" | ||
href={isLink ? this.href : undefined} | ||
rel={isLink && this.target ? 'noreferrer noopener' : undefined} | ||
target={isLink ? this.target : undefined} | ||
onBlur={this.onBlur} | ||
onFocus={this.onFocus} | ||
onClick={this.onClick} | ||
aria-current={isLink && this.isLastItem ? 'location' : undefined} // indicates the last link as the current page | ||
part="item" | ||
> | ||
<span | ||
class={{ | ||
'flex items-center gap-xs2': true, | ||
'text-text-brand': this.isLastItem, | ||
}} | ||
part="content" | ||
> | ||
<slot></slot> | ||
</span> | ||
</TagElem> | ||
<span | ||
class={{ | ||
'breadcrumb-separator': true, | ||
}} | ||
part="separator" | ||
> | ||
<slot name="separator"></slot> | ||
</span> | ||
</div> | ||
); | ||
} | ||
} |
This file contains 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,40 @@ | ||
# bq-breadcrumb-item | ||
|
||
|
||
|
||
<!-- Auto Generated Below --> | ||
|
||
|
||
## Properties | ||
|
||
| Property | Attribute | Description | Type | Default | | ||
| ------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- | ----------------------- | | ||
| `ariaLabel` | `aria-label` | The aria-label that corresponds to the full title of the destination page. This won't be shown in the page, but it will be used by screen readers and other assistive devices. | `string` | `undefined` | | ||
| `href` | `href` | If set, the breadcrumb item will be rendered as an `<a>` with this `href`, otherwise, a `<button>` will be rendered. | `string` | `undefined` | | ||
| `isLastItem` | `is-last-item` | If true, the item is the last element inside breadcrumb | `boolean` | `false` | | ||
| `rel` | `rel` | Where to display the link in the browser context. Relevant only if `href` is set. | `string` | `'noreferrer noopener'` | | ||
| `target` | `target` | Where to display the link in the browser context. Relevant only if `href` is set. | `"_blank" \| "_parent" \| "_self" \| "_top"` | `undefined` | | ||
|
||
|
||
## Events | ||
|
||
| Event | Description | Type | | ||
| --------- | ------------------------------------------ | ------------------------------------------ | | ||
| `bqBlur` | Handler to be called when item loses focus | `CustomEvent<HTMLBqBreadcrumbItemElement>` | | ||
| `bqClick` | Handler to be called when item is clicked | `CustomEvent<HTMLBqBreadcrumbItemElement>` | | ||
| `bqFocus` | Handler to be called when item is focused | `CustomEvent<HTMLBqBreadcrumbItemElement>` | | ||
|
||
|
||
## Shadow Parts | ||
|
||
| Part | Description | | ||
| ------------- | ------------------------------------------ | | ||
| `"base"` | The component wrapper container | | ||
| `"content"` | The `span` tag that loads the content item | | ||
| `"item"` | | | ||
| `"separator"` | The `span` tag that loads the separator | | ||
|
||
|
||
---------------------------------------------- | ||
|
||
*Built with [StencilJS](https://stenciljs.com/)* |
Oops, something went wrong.