Skip to content

chore(components): card web components POC #5491

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

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions packages/components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,20 @@ export namespace Components {
*/
"homeUrl": string;
}
interface PostCard {
/**
* Image position
*/
"imgPosition"?: 'top' | 'bottom';
/**
* Image source
*/
"imgSrc"?: string;
/**
* Variant of the card
*/
"variant"?: 'card' | 'card-product' | 'card-teaser';
}
/**
* @class PostCardControl - representing a stencil component
*/
Expand Down Expand Up @@ -164,6 +178,12 @@ export namespace Components {
*/
"value": string;
}
interface PostCardSection {
/**
* Palette to use on section
*/
"palette"?: 'alternate' | 'default' | 'accent' | 'brand';
}
interface PostClosebutton {
}
interface PostCollapsible {
Expand Down Expand Up @@ -612,6 +632,12 @@ declare global {
prototype: HTMLPostBreadcrumbsElement;
new (): HTMLPostBreadcrumbsElement;
};
interface HTMLPostCardElement extends Components.PostCard, HTMLStencilElement {
}
var HTMLPostCardElement: {
prototype: HTMLPostCardElement;
new (): HTMLPostCardElement;
};
interface HTMLPostCardControlElementEventMap {
"postInput": { state: boolean; value: string };
"postChange": { state: boolean; value: string };
Expand All @@ -633,6 +659,12 @@ declare global {
prototype: HTMLPostCardControlElement;
new (): HTMLPostCardControlElement;
};
interface HTMLPostCardSectionElement extends Components.PostCardSection, HTMLStencilElement {
}
var HTMLPostCardSectionElement: {
prototype: HTMLPostCardSectionElement;
new (): HTMLPostCardSectionElement;
};
interface HTMLPostClosebuttonElement extends Components.PostClosebutton, HTMLStencilElement {
}
var HTMLPostClosebuttonElement: {
Expand Down Expand Up @@ -902,7 +934,9 @@ declare global {
"post-banner": HTMLPostBannerElement;
"post-breadcrumb-item": HTMLPostBreadcrumbItemElement;
"post-breadcrumbs": HTMLPostBreadcrumbsElement;
"post-card": HTMLPostCardElement;
"post-card-control": HTMLPostCardControlElement;
"post-card-section": HTMLPostCardSectionElement;
"post-closebutton": HTMLPostClosebuttonElement;
"post-collapsible": HTMLPostCollapsibleElement;
"post-collapsible-trigger": HTMLPostCollapsibleTriggerElement;
Expand Down Expand Up @@ -1017,6 +1051,20 @@ declare namespace LocalJSX {
*/
"homeUrl"?: string;
}
interface PostCard {
/**
* Image position
*/
"imgPosition"?: 'top' | 'bottom';
/**
* Image source
*/
"imgSrc"?: string;
/**
* Variant of the card
*/
"variant"?: 'card' | 'card-product' | 'card-teaser';
}
/**
* @class PostCardControl - representing a stencil component
*/
Expand Down Expand Up @@ -1066,6 +1114,12 @@ declare namespace LocalJSX {
*/
"value"?: string;
}
interface PostCardSection {
/**
* Palette to use on section
*/
"palette"?: 'alternate' | 'default' | 'accent' | 'brand';
}
interface PostClosebutton {
}
interface PostCollapsible {
Expand Down Expand Up @@ -1373,7 +1427,9 @@ declare namespace LocalJSX {
"post-banner": PostBanner;
"post-breadcrumb-item": PostBreadcrumbItem;
"post-breadcrumbs": PostBreadcrumbs;
"post-card": PostCard;
"post-card-control": PostCardControl;
"post-card-section": PostCardSection;
"post-closebutton": PostClosebutton;
"post-collapsible": PostCollapsible;
"post-collapsible-trigger": PostCollapsibleTrigger;
Expand Down Expand Up @@ -1415,10 +1471,12 @@ declare module "@stencil/core" {
"post-banner": LocalJSX.PostBanner & JSXBase.HTMLAttributes<HTMLPostBannerElement>;
"post-breadcrumb-item": LocalJSX.PostBreadcrumbItem & JSXBase.HTMLAttributes<HTMLPostBreadcrumbItemElement>;
"post-breadcrumbs": LocalJSX.PostBreadcrumbs & JSXBase.HTMLAttributes<HTMLPostBreadcrumbsElement>;
"post-card": LocalJSX.PostCard & JSXBase.HTMLAttributes<HTMLPostCardElement>;
/**
* @class PostCardControl - representing a stencil component
*/
"post-card-control": LocalJSX.PostCardControl & JSXBase.HTMLAttributes<HTMLPostCardControlElement>;
"post-card-section": LocalJSX.PostCardSection & JSXBase.HTMLAttributes<HTMLPostCardSectionElement>;
"post-closebutton": LocalJSX.PostClosebutton & JSXBase.HTMLAttributes<HTMLPostClosebuttonElement>;
"post-collapsible": LocalJSX.PostCollapsible & JSXBase.HTMLAttributes<HTMLPostCollapsibleElement>;
"post-collapsible-trigger": LocalJSX.PostCollapsibleTrigger & JSXBase.HTMLAttributes<HTMLPostCollapsibleTriggerElement>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Component, Element, h, Host, Prop, State } from '@stencil/core';
import { version } from '@root/package.json';

/**
* @slot default - Slot for the section
*/
@Component({
tag: 'post-card-section',
styleUrl: 'post-card-section.scss',
shadow: false,
})
export class PostCardSection {
@Element() host: HTMLPostCardSectionElement;

@State() hasOneInteractiveElement: boolean;

/**
* Palette to use on section
*/
@Prop() palette?: 'alternate' | 'default' | 'accent' | 'brand' = 'default';

private checkIfInteractive() {
const interactiveElements: NodeListOf<HTMLAnchorElement> =
this.host.querySelectorAll('a, button');
this.hasOneInteractiveElement = interactiveElements.length === 1;
console.log(interactiveElements, interactiveElements.length, this.hasOneInteractiveElement);
}

componentWillRender() {
this.checkIfInteractive();
}

render() {
return (
<Host data-version={version} class={'card-body palette-' + this.palette}>
{this.hasOneInteractiveElement && (
<post-linkarea>
<slot></slot>
</post-linkarea>
)}
{!this.hasOneInteractiveElement && <slot></slot>}
</Host>
);
}
}
35 changes: 35 additions & 0 deletions packages/components/src/components/post-card-section/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# post-card

<!-- Auto Generated Below -->


## Properties

| Property | Attribute | Description | Type | Default |
| --------- | --------- | ------------------------- | ------------------------------------------------- | ----------- |
| `palette` | `palette` | Palette to use on section | `"accent" \| "alternate" \| "brand" \| "default"` | `'default'` |


## Slots

| Slot | Description |
| ----------- | -------------------- |
| `"default"` | Slot for the section |


## Dependencies

### Depends on

- [post-linkarea](../post-linkarea)

### Graph
```mermaid
graph TD;
post-card-section --> post-linkarea
style post-card-section fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
5 changes: 5 additions & 0 deletions packages/components/src/components/post-card/post-card.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
117 changes: 117 additions & 0 deletions packages/components/src/components/post-card/post-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { Component, Element, h, Host, Prop, State, Watch } from '@stencil/core';
import { version } from '@root/package.json';
import { checkNonEmpty } from '@/utils';

/**
* @slot default - Slot for the body of the card
* @slot header - Slot for the card header
* @slot footer - Slot for the card footer
*/
@Component({
tag: 'post-card',
styleUrl: 'post-card.scss',
shadow: false,
})
export class PostCard {
@Element() host: HTMLPostCardElement;

@State() hasHeader: boolean;
@State() hasFooter: boolean;
@State() hasOneInteractiveElement: boolean;

/**
* Image source
*/
@Prop() imgSrc?: string;

/**
* Variant of the card
*/
@Prop() variant?: 'card' | 'card-product' | 'card-teaser' = 'card';

/**
* Image position
*/
@Prop() imgPosition?: 'top' | 'bottom' = 'top';

@Watch('imgSrc')
validateImage() {
if (this.variant === 'card-teaser') {
checkNonEmpty(this, 'imgSrc', 'A card teaser requires an image.');
}
}

/**
* Class to be added to the card
*/
private variantClass = 'card';

private checkIfInteractive() {
const interactiveElements: NodeListOf<HTMLAnchorElement> =
this.host.querySelectorAll('a, button');
this.hasOneInteractiveElement = interactiveElements.length === 1;
console.log(interactiveElements, interactiveElements.length, this.hasOneInteractiveElement);
}

componentWillRender() {
this.hasHeader = this.host.querySelectorAll('[slot=header]').length > 0;
this.hasFooter = this.host.querySelectorAll('[slot=footer]').length > 0;

switch (this.variant) {
case 'card':
this.variantClass = 'card';
break;
case 'card-product':
this.variantClass = 'card product-card';
break;
case 'card-teaser':
this.variantClass = 'card teaser-card';
break;
}

if (this.variant === 'card-product') {
this.hasOneInteractiveElement = false;
} else {
this.checkIfInteractive();
}
}

private renderCardContent() {
return (
<div class={this.variantClass}>
{this.imgSrc && this.imgPosition === 'top' && (
<img class={'card-img-' + this.imgPosition} src={this.imgSrc} alt="" />
)}
{this.hasHeader && (
<div class="card-header">
<slot name="header" />
</div>
)}
{this.variant === 'card-product' && <slot />}
{this.variant !== 'card-product' && (
<div class="card-body">
<slot />
</div>
)}

{this.hasFooter && (
<div class="card-footer">
<slot name="footer" />
</div>
)}
{this.imgSrc && this.imgPosition === 'bottom' && (
<img class={'card-img-' + this.imgPosition} src={this.imgSrc} alt="" />
)}
</div>
);
}

render() {
return (
<Host data-version={version}>
{this.hasOneInteractiveElement && <post-linkarea>{this.renderCardContent()}</post-linkarea>}
{!this.hasOneInteractiveElement && this.renderCardContent()}
</Host>
);
}
}
39 changes: 39 additions & 0 deletions packages/components/src/components/post-card/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# post-card

<!-- Auto Generated Below -->


## Properties

| Property | Attribute | Description | Type | Default |
| ------------- | -------------- | ------------------- | ------------------------------------------- | ----------- |
| `imgPosition` | `img-position` | Image position | `"bottom" \| "top"` | `'top'` |
| `imgSrc` | `img-src` | Image source | `string` | `undefined` |
| `variant` | `variant` | Variant of the card | `"card" \| "card-product" \| "card-teaser"` | `'card'` |


## Slots

| Slot | Description |
| ----------- | ----------------------------- |
| `"default"` | Slot for the body of the card |
| `"footer"` | Slot for the card footer |
| `"header"` | Slot for the card header |


## Dependencies

### Depends on

- [post-linkarea](../post-linkarea)

### Graph
```mermaid
graph TD;
post-card --> post-linkarea
style post-card fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
Loading