Skip to content

Commit

Permalink
refactor(button): use slots to render icons
Browse files Browse the repository at this point in the history
refactor(pagination): rewrite button usage to render icons properly

refactor(scroll-top): rewrite button usage to render icons properly

refactor(dropdown): rewrite button usage to render icons properly

refactor(icon): use css custom property to define the icon size

docs(button): reflect changes on how icons are displayed inside buttons
  • Loading branch information
daenub authored May 27, 2024
1 parent 0a8351c commit 4e49ad4
Show file tree
Hide file tree
Showing 15 changed files with 142 additions and 163 deletions.
66 changes: 28 additions & 38 deletions src/components/button/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { html, nothing, LitElement } from "lit"
import { classMap } from "lit/directives/class-map.js"
import { ifDefined } from "lit/directives/if-defined.js"

import { HasSlotController } from "../../lib/hasSlotController.js"
import "../icon/leu-icon.js"
import { HasSlotController } from "../../lib/hasSlotController.js"

import styles from "./button.css"

Expand Down Expand Up @@ -56,6 +56,9 @@ const ARIA_ROLES_SELECTED = [

/**
* @tagname leu-button
* @slot before - The icon to display before the label
* @slot after - The icon to display after the label
* @slot - The label of the button or the icon if no label is set
*/
export class LeuButton extends LitElement {
static styles = styles
Expand All @@ -71,12 +74,14 @@ export class LeuButton extends LitElement {
/**
* @internal
*/
hasSlotController = new HasSlotController(this, ["[default]"])
hasSlotController = new HasSlotController(this, [
"before",
"after",
"[default]",
])

static properties = {
label: { type: String, reflect: true },
icon: { type: String, reflect: true },
iconPosition: { type: String, reflect: true },
size: { type: String, reflect: true },
variant: { type: String, reflect: true },
type: { type: String, reflect: true },
Expand All @@ -95,10 +100,6 @@ export class LeuButton extends LitElement {
/** @type {string} */
this.label = null
/** @type {string} */
this.icon = null
/** @type {("before" | "after")} - Only taken into account if Label and no Icon is set */
this.iconPosition = "before"
/** @type {string} */
this.size = "regular"
/** @type {string} */
this.variant = "primary"
Expand All @@ -124,30 +125,6 @@ export class LeuButton extends LitElement {
this.expanded = undefined
}

getIconSize() {
return this.size === "small" || this.variant === "ghost" ? 16 : 24
}

renderIconBefore() {
if (this.icon && this.iconPosition === "before") {
return html`<div class="icon-wrapper icon-wrapper--before">
<leu-icon name=${this.icon} size=${this.getIconSize()}></leu-icon>
</div>`
}

return nothing
}

renderIconAfter() {
if (this.icon && this.iconPosition === "after") {
return html`<div class="icon-wrapper icon-wrapper--after">
<leu-icon name=${this.icon} size=${this.getIconSize()}></leu-icon>
</div>`
}

return nothing
}

renderExpandingIcon() {
if (typeof this.expanded !== "undefined" && this.variant === "ghost") {
return html`<div class="icon-wrapper icon-wrapper--expanded">
Expand Down Expand Up @@ -175,13 +152,25 @@ export class LeuButton extends LitElement {
return attributes
}

hasTextContent() {
return Array.from(this.childNodes).some(
(node) =>
node.nodeType === node.TEXT_NODE && node.textContent.trim() !== ""
)
}

render() {
const hasContent = this.hasSlotController.test("[default]")
const hasTextContent = this.hasTextContent()
const hasIconDefault = Boolean(this.querySelector("leu-icon"))
const hasIconBefore = this.hasSlotController.test("before")
const hasIconAfter = this.hasSlotController.test("after")
const aria = this.getAriaAttributes()

const cssClasses = {
icon: !hasContent && this.icon,
round: !hasContent && this.icon && this.round,
"icon-only": hasIconDefault && !hasTextContent,
"icon-before": hasIconBefore,
"icon-after": hasIconAfter,
round: this.round,
active: this.active,
inverted: this.inverted,
[this.variant]: true,
Expand All @@ -197,9 +186,10 @@ export class LeuButton extends LitElement {
?disabled=${this.disabled}
type=${this.type}
>
${this.renderIconBefore()}
<span class="label"><slot></slot></span>
${this.renderIconAfter()} ${this.renderExpandingIcon()}
<slot name="before" class="icon-wrapper icon-wrapper--before"></slot>
<span class="content"><slot></slot></span>
<slot name="after" class="icon-wrapper icon-wrapper--after"></slot>
${this.renderExpandingIcon()}
</button>
`
}
Expand Down
18 changes: 10 additions & 8 deletions src/components/button/button.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,13 @@ button {
column-gap: 8px;
}

.label {
.content {
flex: 1 1 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.icon .label {
display: none;
}

button.round {
border-radius: 50%;
}
Expand Down Expand Up @@ -58,7 +54,7 @@ button.regular {
line-height: 24px;
}

button.regular.icon {
button.regular.icon-only {
padding: 12px;
}

Expand All @@ -67,9 +63,11 @@ button.small {
padding: 6px 24px;
font-size: 14px;
line-height: 20px;

--leu-icon-size: 1rem;
}

button.small.icon {
button.small.icon-only {
padding: 8px;
}

Expand Down Expand Up @@ -125,6 +123,8 @@ button.secondary:disabled {

/* ghost */
button.ghost {
--leu-icon-size: 1rem;

background: transparent;
padding: 0 0.5rem;
color: var(--leu-color-black-60);
Expand Down Expand Up @@ -207,7 +207,9 @@ button.ghost.inverted:disabled {
display: block;
}

.ghost :is(.icon-wrapper--before, .icon-wrapper--after) {
.ghost.icon-before .icon-wrapper--before,
.ghost.icon-after .icon-wrapper--after {
display: block;
padding: 0.5rem;
border-radius: 50%;
background: var(--leu-color-black-transp-10);
Expand Down
75 changes: 58 additions & 17 deletions src/components/button/stories/button.stories.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { html } from "lit"
import { html, nothing } from "lit"
import { ifDefined } from "lit/directives/if-defined.js"
import { classMap } from "lit/directives/class-map.js"
import "../leu-button.js"
import "../../icon/leu-icon.js"
import { paths as iconPaths } from "../../icon/paths.js"
import {
BUTTON_VARIANTS,
Expand Down Expand Up @@ -35,8 +36,6 @@ function Template(args = {}) {
content=${ifDefined(args.content)}
size=${ifDefined(args.size)}
variant=${ifDefined(args.variant)}
icon=${ifDefined(args.icon)}
iconPosition=${ifDefined(args.iconPosition)}
type=${ifDefined(args.type)}
expanded=${ifDefined(args.expanded)}
?round=${args.round}
Expand All @@ -45,6 +44,12 @@ function Template(args = {}) {
?disabled=${args.disabled}
@click=${copyContent}
>
${args.icon
? html`<leu-icon
slot=${ifDefined(args.content ? args.iconPosition : undefined)}
name=${args.icon}
></leu-icon>`
: nothing}
${args.content}
</leu-button>
</div>
Expand All @@ -70,13 +75,18 @@ function Template(args = {}) {

export const Regular = Template.bind({})
Regular.argTypes = {
content: { type: "string" },
content: { control: "text" },
icon: { control: "select", options: Object.keys(iconPaths) },
iconPosition: { control: "select", options: ["before", "after"] },
iconPosition: {
control: "select",
options: ["before", "after"],
},
type: { control: "radio", options: BUTTON_TYPES },
size: { control: "radio", options: BUTTON_SIZES },
variant: { control: "radio", options: BUTTON_VARIANTS },
expanded: { control: "radio", options: BUTTON_EXPANDED_OPTIONS },
disabled: { control: "boolean" },
round: { control: "boolean" },
}
Regular.args = {
content: "Click Mich...",
Expand All @@ -86,7 +96,7 @@ Regular.args = {
inverted: false,

icon: null,
iconPosition: null,
iconPosition: "before",
size: null,
variant: null,
type: null,
Expand All @@ -97,9 +107,14 @@ const items = [
{ content: "Active", active: true },
{ content: "Disabled", disabled: true },

{ content: "Normal", icon: "calendar" },
{ content: "Active", icon: "calendar", active: true },
{ content: "Disabled", icon: "calendar", disabled: true },
{ content: "Normal", icon: "calendar", iconPosition: "before" },
{ content: "Active", icon: "calendar", iconPosition: "before", active: true },
{
content: "Disabled",
icon: "calendar",
iconPosition: "before",
disabled: true,
},

{ content: "Normal", icon: "calendar", iconPosition: "after" },
{ content: "Active", icon: "calendar", iconPosition: "after", active: true },
Expand All @@ -120,13 +135,35 @@ const items = [
]

const ghostItems = [
{ content: "Normal", icon: "calendar" },
{ content: "Active", icon: "calendar", active: true },
{ content: "Disabled", icon: "calendar", disabled: true },
{ content: "Normal", icon: "calendar", iconPosition: "before" },
{ content: "Active", icon: "calendar", iconPosition: "before", active: true },
{
content: "Disabled",
icon: "calendar",
iconPosition: "before",
disabled: true,
},

{ content: "Normal", icon: "calendar", expanded: "closed" },
{ content: "Active", icon: "calendar", active: true, expanded: "closed" },
{ content: "Disabled", icon: "calendar", disabled: true, expanded: "closed" },
{
content: "Normal",
icon: "calendar",
iconPosition: "before",
expanded: "closed",
},
{
content: "Active",
icon: "calendar",
iconPosition: "before",
active: true,
expanded: "closed",
},
{
content: "Disabled",
icon: "calendar",
iconPosition: "before",
disabled: true,
expanded: "closed",
},

{ content: "Normal", icon: "calendar", iconPosition: "after" },
{ content: "Active", icon: "calendar", iconPosition: "after", active: true },
Expand Down Expand Up @@ -269,15 +306,19 @@ function TemplateOverview() {
label=${ifDefined(item.label)}
size=${ifDefined(size.size)}
variant=${ifDefined(group.variant)}
icon=${ifDefined(item.icon)}
iconPosition=${ifDefined(item.iconPosition)}
expanded=${ifDefined(item.expanded)}
?round=${item.round}
?active=${item.active}
?disabled=${item.disabled}
?inverted=${group.inverted}
@click=${copyContent}
>
${item.icon
? html` <leu-icon
slot=${ifDefined(item.iconPosition)}
name=${item.icon}
></leu-icon>`
: nothing}
${item.content}
</leu-button>
`
Expand Down
Loading

0 comments on commit 4e49ad4

Please sign in to comment.