Skip to content

Commit

Permalink
Merge pull request #111 from amir78729/docs/jsdoc/row
Browse files Browse the repository at this point in the history
docs: add JSDoc to `row` component
  • Loading branch information
amir78729 authored May 28, 2024
2 parents c4732e0 + 17864bc commit 86dbba9
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 80 deletions.
57 changes: 52 additions & 5 deletions src/row/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,61 @@
import { customElement } from "lit/decorators.js";
import { Row } from "./row";
import styles from "./row.style";
import { customElement } from 'lit/decorators.js';
import { Row } from './row';
import styles from './row.style';

@customElement("tap-row")
/**
* ### Example
*
*
* ##### Simple
*
* ```html
* <tap-row>
* <div slot="leading">Leading content</div>
* <div slot="content">Main content</div>
* <div slot="trailing">Trailing content</div>
* </tap-row>
* ```
*
* ##### Navigable Row
*
* ```html
* <tap-row navigable>
* <div slot="leading">Leading content</div>
* <div slot="content">Main content</div>
* <div slot="trailing">Trailing content</div>
* </tap-row>
* ```
*
* @summary A flexible row component with leading, content, and trailing slots.
*
* @prop {`'standard'` \| `'compact'`} [`size`=`'compact'`] - The size of the row. Defaults to `standard`.
* @prop {`boolean`} [`navigable`=`false`] - Indicates whether the row is navigable (clickable).
*
* @csspart [`row`] - The main container for the row.
* @csspart [`leading`] - The container for the leading slot.
* @csspart [`content`] - The container for the content slot.
* @csspart [`trailing`] - The container for the trailing slot.
* @csspart [`navigable`] - The container for the navigable icon.
*
* @cssprop [`--tap-font-family`=`--tap-sys-font-family`] - The font family used in the row.
* @cssprop [`--tap-row-background-color`=`--tap-palette-white`] - The background color of the row.
* @cssprop [`--tap-row-leading-vertical-padding`] - The vertical padding for the leading slot.
* @cssprop [`--tap-row-leading-horizontal-padding`=`--tap-sys-spacing-4`] - The horizontal padding for the leading slot.
* @cssprop [`--tap-row-content-padding`=`--tap-sys-spacing-4`] - The padding for the content slot.
* @cssprop [`--tap-row-trailing-vertical-padding`] - The vertical padding for the trailing slot.
* @cssprop [`--tap-row-trailing-horizontal-padding`=`--tap-sys-spacing-4`] - The horizontal padding for the trailing slot.
* @cssprop [`--tap-row-standard-height`=`--tap-sys-spacing-13`] - The height of the standard size row.
* @cssprop [`--tap-row-compact-height`=`--tap-sys-spacing-12`] - The height of the compact size row.
*
* @event slotchange - Dispatched when the content of any slot changes.
*/
@customElement('tap-row')
export class TapRow extends Row {
static readonly styles = [styles];
}

declare global {
interface HTMLElementTagNameMap {
"tap-row": TapRow;
'tap-row': TapRow;
}
}
103 changes: 58 additions & 45 deletions src/row/row.stories.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
import {html, nothing, TemplateResult} from "lit";
import "./index";
import "../button";
import "../icons";
import "../checkbox";
import "../radio";
import "../badge";
import "../avatar";
import { html, nothing, TemplateResult } from 'lit';
import './index';
import '../button';
import '../icons';
import '../checkbox';
import '../radio';
import '../badge';
import '../avatar';

export default {
title: "Row",
component: "tap-row",
title: 'Row',
component: 'tap-row',
argTypes: {
size: {
description: "Row size",
control: {type: "inline-radio"},
description: 'Row size',
control: { type: 'inline-radio' },
options: ['standard', 'compact'],
defaultValue: 'standard',
},
navigable: {
description: "Navigable (Show Chevron)",
control: {type: "boolean"},
description: 'Navigable (Show Chevron)',
control: { type: 'boolean' },
defaultValue: false,
},
leading: {
description: "Row leading slot",
control: {type: "select"},
description: 'Row leading slot',
control: { type: 'select' },
options: ['icon', 'nothing', 'radio', 'checkbox', 'avatar'],
defaultValue: 'nothing',
},
trailing: {
description: "Row trailing slot",
control: {type: "select"},
description: 'Row trailing slot',
control: { type: 'select' },
options: ['icon', 'button', 'badge', 'ghost-button', 'price', 'nothing'],
defaultValue: 'nothing',
},
content: {
description: "Row content slot.",
control: {type: "select"},
description: 'Row content slot.',
control: { type: 'select' },
options: ['standard', 'reverse', 'address', 'customized', 'nothing'],
defaultValue: 'nothing',
},
Expand All @@ -58,58 +58,71 @@ interface ArgTypes {
navigable: boolean;
}

const renderExampleSideSlot = (example: unknown, type: 'leading' | 'trailing') => {
const renderExampleSideSlot = (
example: unknown,
type: 'leading' | 'trailing',
) => {
switch (example) {
case 'badge':
return html`
<tap-badge slot=${type} value="۱" variant="error" type="numeral"></tap-badge>`;
return html` <tap-badge
slot=${type}
value="۱"
variant="error"
type="numeral"
></tap-badge>`;
case 'icon':
return html`
<tap-icon-default slot=${type}></tap-icon-default>`;
return html` <tap-icon-default slot=${type}></tap-icon-default>`;
case 'button':
return html`
<tap-button slot=${type}>Button</tap-button>`;
return html` <tap-button slot=${type}>Button</tap-button>`;
case 'ghost-button':
return html`
<tap-button variant="ghost" slot=${type}>Button</tap-button>`;
return html` <tap-button variant="ghost" slot=${type}
>Button</tap-button
>`;
case 'checkbox':
return html`
<tap-checkbox slot=${type}></tap-checkbox>`;
return html` <tap-checkbox slot=${type}></tap-checkbox>`;
case 'radio':
return html`
<tap-radio slot=${type}></tap-radio>`;
return html` <tap-radio slot=${type}></tap-radio>`;
case 'avatar':
return html`
<tap-avatar size="small" slot=${type} image="https://picsum.photos/100"></tap-avatar>`;
return html` <tap-avatar
size="small"
slot=${type}
image="https://picsum.photos/100"
></tap-avatar>`;
case 'price':
return html`<p slot=${type}>۱۵۷٬۰۰۰ تومان</p>`;
default:
return nothing;
}
}
};

const renderExampleContentSlot = (example: unknown) => {
switch (example) {
case "customized":
case 'customized':
return html`<h1 slot="content">any content you want! 😉</h1>`;
case "standard":
case 'standard':
return html`<div slot="content">
<h3 style="margin: 0;">عنوان را وارد کنید</h3>
<p style="margin: 0;">توضیحات لیست</p>
</div>`
case "reverse":
</div>`;
case 'reverse':
return html`<div slot="content">
<p style="margin: 0;">عنوان را وارد کنید</p>
<h3 style="margin: 0;">توضیحات لیست</h3>
</div>`
case "address":
return html`<p slot="content">سعادت‌آباد، بلوار بهزاد</p>`
</div>`;
case 'address':
return html`<p slot="content">سعادت‌آباد، بلوار بهزاد</p>`;
default:
return nothing;
}
}
};

const Template: Story<ArgTypes> = ({size, leading, trailing, navigable, content}: ArgTypes) => html`
const Template: Story<ArgTypes> = ({
size,
leading,
trailing,
navigable,
content,
}: ArgTypes) => html`
<tap-row ?navigable=${navigable} size=${size}>
${renderExampleSideSlot(leading, 'leading')}
${renderExampleContentSlot(content)}
Expand Down
16 changes: 9 additions & 7 deletions src/row/row.style.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { css } from "lit";
import { css } from 'lit';

export default css`
:host {
Expand All @@ -15,7 +15,7 @@ export default css`
display: none !important;
}
.container{
.container {
display: flex;
align-items: stretch;
width: 100%;
Expand All @@ -25,22 +25,24 @@ export default css`
}
.leading {
padding: var(--tap-row-leading-vertical-padding, 0) var(--tap-row-leading-horizontal-padding, var(--tap-sys-spacing-4));
padding: var(--tap-row-leading-vertical-padding, 0)
var(--tap-row-leading-horizontal-padding, var(--tap-sys-spacing-4));
display: flex;
align-items: center;
justify-content: center;
}
.content {
padding: var(--tap-row-content-padding ,var(--tap-sys-spacing-4));
padding: var(--tap-row-content-padding, var(--tap-sys-spacing-4));
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.trailing {
padding: var(--tap-row-trailing-vertical-padding, 0) var(--tap-row-trailing-horizontal-padding, var(--tap-sys-spacing-4));
padding: var(--tap-row-trailing-vertical-padding, 0)
var(--tap-row-trailing-horizontal-padding, var(--tap-sys-spacing-4));
display: flex;
align-items: center;
justify-content: center;
Expand All @@ -52,11 +54,11 @@ export default css`
justify-content: center;
}
:host([size="standard"]) .container {
:host([size='standard']) .container {
height: var(--tap-row-standard-height, var(--tap-sys-spacing-13));
}
:host([size="compact"]) .container {
:host([size='compact']) .container {
height: var(--tap-row-compact-height, var(--tap-sys-spacing-12));
}
Expand Down
69 changes: 46 additions & 23 deletions src/row/row.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import {html, LitElement, PropertyValues} from "lit";
import {property} from "lit/decorators.js";
import { html, LitElement, PropertyValues } from 'lit';
import { property } from 'lit/decorators.js';

export class Row extends LitElement {
@property({ reflect: true }) size: "standard" | "compact" = "standard";
@property({ reflect: true }) size: 'standard' | 'compact' = 'standard';

@property({ type: Boolean, reflect: true }) navigable: boolean = false;

private hasSlotContent(slotName: string): boolean {
const slot = this.shadowRoot?.querySelector(`slot[name="${slotName}"]`) as HTMLSlotElement;
return slot?.assignedNodes({flatten: true}).length > 0;
const slot = this.shadowRoot?.querySelector(
`slot[name="${slotName}"]`,
) as HTMLSlotElement;
return slot?.assignedNodes({ flatten: true }).length > 0;
}

private hideSlotContainerIfNotExists(slotName: string) {
Expand All @@ -24,8 +26,11 @@ export class Row extends LitElement {
this.hideSlotContainerIfNotExists('trailing');
['title', 'subtitle'].forEach((id) => {
const element = this.shadowRoot?.getElementById(id);
if (element) element.style.display = this.hasSlotContent('content') ? 'none' : 'block'
})
if (element)
element.style.display = this.hasSlotContent('content')
? 'none'
: 'block';
});
}

private getDirection() {
Expand All @@ -35,14 +40,15 @@ export class Row extends LitElement {
element = element.parentElement;
direction = getComputedStyle(element).direction;
}
return direction
return direction;
}

private changeNavigableDirections() {
if (this.navigable) {
const direction = this.getDirection();
const navigableElement = this.shadowRoot?.getElementById('navigable');
if (navigableElement) navigableElement.style.transform = `rotate(${direction === 'ltr' ? '180' : '0'}deg)`;
if (navigableElement)
navigableElement.style.transform = `rotate(${direction === 'ltr' ? '180' : '0'}deg)`;
}
}

Expand All @@ -54,28 +60,45 @@ export class Row extends LitElement {

private renderNavigableIcon() {
return html`
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.9143 8.46445L10.3794 11.9993L13.9143 15.5355L12.5 16.9497L7.55029 12L12.5 7.05023L13.9143 8.46445Z" fill="#B1B2B2"/>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M13.9143 8.46445L10.3794 11.9993L13.9143 15.5355L12.5 16.9497L7.55029 12L12.5 7.05023L13.9143 8.46445Z"
fill="#B1B2B2"
/>
</svg>
`
`;
}

protected render(): unknown {
return html`
<div class="container" part="row">
<span class="leading" part="leading">
<slot name="leading" @slotchange="${this.updateSlotsVisibility}"></slot>
<slot
name="leading"
@slotchange="${this.updateSlotsVisibility}"
></slot>
</span>
<span class="content" part="content">
<slot name="content" @slotchange=${this.updateSlotsVisibility}></slot>
</span>
<span class="trailing" part="trailing">
<slot
name="trailing"
@slotchange="${this.updateSlotsVisibility}"
></slot>
</span>
<span id="navigable" part="navigable">
${this.renderNavigableIcon()}
</span>
<span class="content" part="content">
<slot name="content" @slotchange=${this.updateSlotsVisibility}></slot>
</span>
<span class="trailing" part="trailing">
<slot name="trailing" @slotchange="${this.updateSlotsVisibility}"></slot>
</span>
<span id="navigable" part="navigable">
${this.renderNavigableIcon()}
</span>
</div>
</div>
`;
}
}

0 comments on commit 86dbba9

Please sign in to comment.