diff --git a/src/row/index.ts b/src/row/index.ts index 656dc23e..70d13182 100644 --- a/src/row/index.ts +++ b/src/row/index.ts @@ -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 + * + *
Leading content
+ *
Main content
+ *
Trailing content
+ *
+ * ``` + * + * ##### Navigable Row + * + * ```html + * + *
Leading content
+ *
Main content
+ *
Trailing content
+ *
+ * ``` + * + * @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; } } diff --git a/src/row/row.stories.ts b/src/row/row.stories.ts index 0d363ecc..1bd1c292 100644 --- a/src/row/row.stories.ts +++ b/src/row/row.stories.ts @@ -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', }, @@ -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` - `; + return html` `; case 'icon': - return html` - `; + return html` `; case 'button': - return html` - Button`; + return html` Button`; case 'ghost-button': - return html` - Button`; + return html` Button`; case 'checkbox': - return html` - `; + return html` `; case 'radio': - return html` - `; + return html` `; case 'avatar': - return html` - `; + return html` `; case 'price': return html`

۱۵۷٬۰۰۰ تومان

`; default: return nothing; } -} +}; const renderExampleContentSlot = (example: unknown) => { switch (example) { - case "customized": + case 'customized': return html`

any content you want! 😉

`; - case "standard": + case 'standard': return html`

عنوان را وارد کنید

توضیحات لیست

-
` - case "reverse": + `; + case 'reverse': return html`

عنوان را وارد کنید

توضیحات لیست

-
` - case "address": - return html`

سعادت‌آباد، بلوار بهزاد

` + `; + case 'address': + return html`

سعادت‌آباد، بلوار بهزاد

`; default: return nothing; } -} +}; -const Template: Story = ({size, leading, trailing, navigable, content}: ArgTypes) => html` +const Template: Story = ({ + size, + leading, + trailing, + navigable, + content, +}: ArgTypes) => html` ${renderExampleSideSlot(leading, 'leading')} ${renderExampleContentSlot(content)} diff --git a/src/row/row.style.ts b/src/row/row.style.ts index c249ef63..4446d419 100644 --- a/src/row/row.style.ts +++ b/src/row/row.style.ts @@ -1,4 +1,4 @@ -import { css } from "lit"; +import { css } from 'lit'; export default css` :host { @@ -15,7 +15,7 @@ export default css` display: none !important; } - .container{ + .container { display: flex; align-items: stretch; width: 100%; @@ -25,14 +25,15 @@ 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; @@ -40,7 +41,8 @@ export default css` } .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; @@ -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)); } diff --git a/src/row/row.ts b/src/row/row.ts index 712c147b..f3187e1c 100644 --- a/src/row/row.ts +++ b/src/row/row.ts @@ -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) { @@ -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() { @@ -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)`; } } @@ -54,28 +60,45 @@ export class Row extends LitElement { private renderNavigableIcon() { return html` - - + + - ` + `; } protected render(): unknown { return html`
- + + + + + + + + + + ${this.renderNavigableIcon()} - - - - - - - - ${this.renderNavigableIcon()} - -
+ `; } }