vira
Version:
A simple and highly versatile design system using element-vir.
141 lines (131 loc) • 5.32 kB
JavaScript
import { css, html, nothing } from 'element-vir';
import { viraBorders } from '../styles/border.js';
import { viraDisabledStyles } from '../styles/disabled.js';
import { viraAnimationDurations } from '../styles/durations.js';
import { createFocusStyles, viraFocusCssVars } from '../styles/focus.js';
import { noUserSelect } from '../styles/index.js';
import { noNativeFormStyles } from '../styles/native-styles.js';
import { defineViraElement } from './define-vira-element.js';
import { ViraIcon } from './vira-icon.element.js';
/**
* Button styles available for {@link ViraButton}.
*
* @category Button
*/
export var ViraButtonStyle;
(function (ViraButtonStyle) {
ViraButtonStyle["Default"] = "vira-button-default";
ViraButtonStyle["Outline"] = "vira-button-outline";
})(ViraButtonStyle || (ViraButtonStyle = {}));
/**
* A custom button with default styling.
*
* @category Button
* @category Elements
* @see https://electrovir.github.io/element-vir/vira/book/elements/vira-button
*/
export const ViraButton = defineViraElement()({
tagName: 'vira-button',
hostClasses: {
'vira-button-outline-style': ({ inputs }) => inputs.buttonStyle === ViraButtonStyle.Outline,
'vira-button-disabled': ({ inputs }) => !!inputs.disabled,
'vira-button-expand-to-fit-icon': ({ inputs }) => !!inputs.expandToFitIcon,
},
cssVars: {
/** On the default button style this is the background color. */
'vira-button-primary-color': '#0a89ff',
'vira-button-primary-hover-color': '#59b1ff',
'vira-button-primary-active-color': '#007ff6',
/** On the default button style this is the text color. */
'vira-button-secondary-color': '#ffffff',
'vira-button-padding': '5px 10px',
'vira-button-internal-foreground-color': '',
'vira-button-internal-background-color': '',
},
styles: ({ hostClasses, cssVars }) => css `
:host {
font-weight: bold;
display: inline-flex;
position: relative;
vertical-align: middle;
align-items: center;
box-sizing: border-box;
${noUserSelect};
${cssVars['vira-button-internal-background-color'].name}: ${cssVars['vira-button-primary-color'].value};
${cssVars['vira-button-internal-foreground-color'].name}: ${cssVars['vira-button-secondary-color'].value};
${viraFocusCssVars['vira-focus-outline-color'].name}: ${cssVars['vira-button-primary-hover-color'].value}
}
:host(:hover) button,
button:hover {
${cssVars['vira-button-internal-background-color'].name}: ${cssVars['vira-button-primary-hover-color'].value};
}
:host(:active) button,
button:active {
${cssVars['vira-button-internal-background-color'].name}: ${cssVars['vira-button-primary-active-color'].value};
}
${hostClasses['vira-button-disabled'].selector} {
${viraDisabledStyles};
}
${hostClasses['vira-button-outline-style'].selector} button {
color: ${cssVars['vira-button-internal-background-color'].value};
background-color: transparent;
border-color: currentColor;
}
button {
${noNativeFormStyles};
cursor: pointer;
position: relative;
width: 100%;
height: 100%;
border: 2px solid transparent;
box-sizing: border-box;
display: inline-flex;
justify-content: center;
align-items: center;
border-radius: ${viraBorders['vira-form-input-radius'].value};
background-color: ${cssVars['vira-button-internal-background-color'].value};
color: ${cssVars['vira-button-internal-foreground-color'].value};
padding: ${cssVars['vira-button-padding'].value};
transition:
color ${viraAnimationDurations['vira-interaction-animation-duration'].value},
background-color
${viraAnimationDurations['vira-interaction-animation-duration'].value},
border-color ${viraAnimationDurations['vira-interaction-animation-duration'].value};
${createFocusStyles({
elementBorderSize: 2,
})}
}
.empty-text {
width: 0;
}
button ${ViraIcon} + .text-template {
margin-left: 8px;
}
:host(:not(.${hostClasses['vira-button-expand-to-fit-icon'].name})) {
& ${ViraIcon} {
height: 0;
display: flex;
align-items: center;
}
}
`,
render: ({ inputs }) => {
const iconTemplate = inputs.icon
? html `
<${ViraIcon.assign({
icon: inputs.icon,
})}></${ViraIcon}>
`
: nothing;
const textTemplate = inputs.text
? html `
<span class="text-template">${inputs.text}</span>
`
: html `
<span class="empty-text"> </span>
`;
return html `
<button ?disabled=${inputs.disabled}>${iconTemplate} ${textTemplate}</button>
`;
},
});