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(card): redefine interface #1131

Merged
merged 22 commits into from
Apr 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 21 additions & 15 deletions __snapshots__/Card.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,29 @@
<slot name="media">
</slot>
</div>
<div class="vwc-card-info">
<header class="no-content">
<div class="vwc-card-header">
<slot name="graphics">
</slot>
<div class="vwc-card-title">
<div class="vwc-card-content">
<slot name="content">
<header class="no-content vwc-card-header">
<div class="vwc-card-header-content">
<slot name="graphic">
</slot>
<div>
<div class="vwc-card-title">
</div>
<div class="vwc-card-subtitle">
</div>
</div>
</div>
<slot name="meta">
</slot>
</header>
<div class="vwc-card-text">
</div>
<div class="vwc-card-subtitle">
</div>
</header>
<div class="vwc-card-supportText">
</div>
<div class="no-content vwc-card-actions">
<slot name="actions">
</slot>
</div>
</slot>
</div>
<div class="no-content vwc-card-footer">
<slot name="footer">
</slot>
</div>
</div>

Expand Down
30 changes: 14 additions & 16 deletions components/card/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ Cards contain content and actions about a single subject.

```
<vwc-card heading="Hello Card!"
icon="home"
badge-content="This is the badge content"
>
icon="home">
<div slot="media">Some media</div>
<div>This is my content</div>
<vwc-button slot="actions">Action Button</vwc-button>
</vwc-card>
```
Expand All @@ -20,21 +17,22 @@ Cards contain content and actions about a single subject.

### Properties/Attributes

|name|attr/prop/reflected|type|description|
|--- |--- |--- |--- |
|`heading`|reflected|string|The heading text|
|`header-icon`|reflected|string|A valid vivid icon type|
|`badge-content`|reflected|string|A content to show in a badge (for info and CTA modes)|
|`layout`|reflected|`large` | `basic`|Sets large or basic heading and header icon. Basic is the default.|
|name|attr/prop/reflected|type| description |
|--- |--- |--- |----------------------|
|`heading`|reflected|string| The heading text |
|`subtitle`|reflected|string| The sub-heading text |
|`card-text`|reflected|string| The card text |
|`header-icon`|reflected|string| A valid vivid icon type |

### Slots

|name|description|
|--- |--- |
|`graphics`|Content to show in the header icon section. If exists, overrides the `icon` attribute’s definition|
|`actions`|Content to show in the actions section. If exists, overrides the `action-icon` and `action-text` attributes definitions|
|`media`|Slot to add anything inside the `media` area|

| name | description |
|------------|----------------------------------------------------------------------------------------------------|
| `graphics` | Content to show in the header icon section. If exists, overrides the `header-icon` attribute’s definition |
| `meta` | Slot for action content in the card header |
| `media` | Slot to add anything inside the `media` area |
| `footer` | Slot for action content placed the card footer |
| `content` | Slot for content of the card. If exist, overrides the `heading`, `subtitle`, `card-text` and `header-icon`
## Styling tips

### Setting card's width
Expand Down
51 changes: 32 additions & 19 deletions components/card/src/vwc-card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,25 @@
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.05), 0 8px 8px rgba(0, 0, 0, 0.05), 0 2px 16px rgba(0, 0, 0, 0.1);
color: var(#{scheme-variables.$vvd-color-on-canvas});

&-info {
&-content {
display: flex;
flex-flow: column;
padding: 24px;
padding: 1.5rem;
}

&-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 0.5rem;

:host([text]) & {
margin-bottom: 12px;
}

&-content {
display: inline-flex;
}
}

&-title,
Expand All @@ -35,7 +46,6 @@

&-title {
@include typography.typography-cat-shorthand('subtitle-2');
margin-bottom: 4px;
-webkit-line-clamp: var(#{card-variables.$title-line-clamp});
}

Expand All @@ -44,41 +54,44 @@
}

&-subtitle,
&-supportText {
&-text {
@include typography.typography-cat-shorthand('body-2');
color: var(#{scheme-variables.$vvd-color-neutral-70});
}

&-actions {
&-text {
padding-right: 0.5rem;
}

&-footer {
display: inline-flex;
flex-direction: column;
align-items: flex-end;
margin-top: 16px;
padding-bottom: 1.5rem;
margin-top: auto;
padding-inline: 1.5rem;
}
}

header {
display: inline-flex;
flex-direction: column;
align-content: space-between;

:host([supporting-text]) & {
margin-bottom: 12px;
}
}

::slotted([slot="graphics"i]),
.header-icon {
::slotted([slot="graphic"i]),
.icon {
flex-shrink: 0;
align-self: baseline;
margin: 4px 10px 0 0;
}

.header-icon {
.icon {
width: 20px;
height: 20px;
}

::slotted([slot="meta"i]) {
flex-shrink: 0;
align-self: flex-start;
margin-block-start: -0.5rem;
margin-inline-end: -0.5rem;
}

.no-content {
display: none;
}
Expand Down
69 changes: 38 additions & 31 deletions components/card/src/vwc-card.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
customElement, html, LitElement,
} from 'lit-element';
import { nothing } from 'lit-html';
import { style } from './vwc-card.css.js';
import { property } from 'lit-element/lib/decorators.js';
import { classMap } from 'lit-html/directives/class-map.js';
import '@vonage/vwc-button';
import '@vonage/vwc-icon';


declare global {
interface HTMLElementTagNameMap {
'vwc-card': VWCCard;
Expand Down Expand Up @@ -39,82 +41,87 @@ export class VWCCard extends LitElement {

@property({
reflect: true,
attribute: 'header-icon',
attribute: 'icon',
type: String
})
headerIcon: string | null = null;
icon: string | null = null;

@property({
reflect: true,
attribute: 'supporting-text',
attribute: 'text',
type: String
})
supportingText: string | undefined;
text: string | undefined;

private headerIconSlottedItems?: Node[];
private shouldShowActionsSlot: boolean | undefined;
private IconSlottedItems?: Node[];
#shouldShowFooterSlot: boolean | undefined;

private get headerContentExists(): boolean {
return Boolean(this.heading || this.subtitle || this.headerIcon || this.headerIconSlottedItems?.length);
return Boolean(this.heading || this.subtitle || this.icon || this.IconSlottedItems?.length);
}

private get headerClass(): string {
return (this.headerContentExists) ? '' : 'no-content';
}

protected override render(): unknown {
const actionsClassMap = {
'no-content': !(this.shouldShowActionsSlot)
const footerClassMap = {
'no-content': !(this.#shouldShowFooterSlot)
};
return html`
<div class="vwc-card">
<div class="vwc-card-media">
<slot name="media"></slot>
yinonov marked this conversation as resolved.
Show resolved Hide resolved
</div>
<div class="vwc-card-info">
${this.renderHeader()}
<div class="vwc-card-supportText">
${this.supportingText ? this.supportingText : ''}
rachelbt marked this conversation as resolved.
Show resolved Hide resolved
</div>
<div class="vwc-card-actions ${classMap(actionsClassMap)}">
<slot name="actions" @slotchange="${this.actionsSlotChanged}"></slot>
</div>
<div class="vwc-card-content">
yinonov marked this conversation as resolved.
Show resolved Hide resolved
<slot name="content">
${this.renderHeader()}
<div class="vwc-card-text">
${this.text ? this.text : nothing}
</div>
</slot>
</div>
<div class="vwc-card-footer ${classMap(footerClassMap)}">
<slot name="footer" @slotchange="${this.footerSlotChanged}"></slot>
</div>
</div>
`;
}

private renderHeader() {
return html`
<header class="${this.headerClass}">
<div class="vwc-card-header">
<slot name="graphics" @slotchange="${this.graphicsSlotChanged}">
${this.headerIcon ? this.renderIcon() : ''}
</slot>
<div class="vwc-card-title">${this.heading}</div>
<header class="vwc-card-header ${this.headerClass}">
<div class="vwc-card-header-content">
<slot name="graphic" @slotchange="${this.graphicSlotChanged}">
${this.icon ? this.renderIcon() : ''}
</slot>
<div>
<div class="vwc-card-title">${this.heading}</div>
<div class="vwc-card-subtitle">${this.subtitle}</div>
</div>
</div>
<div class="vwc-card-subtitle">${this.subtitle}</div>
<slot name="meta"></slot>
yinonov marked this conversation as resolved.
Show resolved Hide resolved
</header>`;
}

private renderIcon() {
return html`<vwc-icon class="header-icon" inline type="${this.headerIcon}"></vwc-icon>`;
return html`<vwc-icon class="icon" inline type="${this.icon}"></vwc-icon>`;
}

private graphicsSlotChanged() {
private graphicSlotChanged() {
const headerElement = this.shadowRoot?.querySelector('header');
const slot = headerElement?.querySelector('slot[name="graphics"]') as HTMLSlotElement;
this.headerIconSlottedItems = slot.assignedNodes();
const slot = headerElement?.querySelector('slot[name="graphic"]') as HTMLSlotElement;
this.IconSlottedItems = slot.assignedNodes();
if (this.headerContentExists) {
headerElement?.classList.remove('no-content');
} else {
headerElement?.classList.add('no-content');
}
}

private actionsSlotChanged(): void {
const slot = this.shadowRoot?.querySelector('slot[name="actions"]') as HTMLSlotElement;
this.shouldShowActionsSlot = Boolean(slot.assignedNodes().length);
private footerSlotChanged(): void {
const slot = this.shadowRoot?.querySelector('slot[name="footer"]') as HTMLSlotElement;
this.#shouldShowFooterSlot = Boolean(slot.assignedNodes().length);
this.requestUpdate();
}
}
18 changes: 1 addition & 17 deletions components/card/stories/arg-types.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,4 @@
export const argTypes = {
layout: {
control: {
type: 'select',
options: ['large', 'basic'],
}
},
icon: {
control: {
type: 'input',
}
},
'badge-content': {
control: {
type: 'input'
}
},
styles: { table: { disable: true } },

};