Skip to content
This repository has been archived by the owner on Jan 6, 2022. It is now read-only.

Buttonify #282

Merged
merged 16 commits into from
Mar 2, 2017
Merged
166 changes: 128 additions & 38 deletions elements/button.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
'use strict'

const html = require('choo/html')
const assert = require('assert')
const css = require('sheetify')
const icon = require('./icon')
const xtend = require('xtend')

const prefix = css`
const baseStyles = css`
:host {
text-transform: uppercase;
letter-spacing: .025em;
.btn-wrapper {
.btn-inner-wrapper {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
Expand All @@ -17,71 +18,160 @@ const prefix = css`
}
}
.icon-only {
.btn-text {
display: none;
}
.btn-text { display: none }
}
.filled-green {
`

var greenStyles = css`
:host {
padding: .5rem .75rem;
font-size: .75rem;
background-color: var(--color-green);
color: var(--color-neutral-04);
}
.filled-green:hover,
.filled-green:focus {
:host:hover,
:host:focus {
background-color: var(--color-green-hover);
color: var(--color-white);
}
.filled-red {
`

var redStyles = css`
:host {
padding: .5rem .75rem;
font-size: .75rem;
background-color: var(--color-red);
color: var(--color-neutral-04);
}
.filled-red:hover,
.filled-red:focus {
:host:hover,
:host:focus {
background-color: var(--color-red-hover);
color: var(--color-white);
}
.plain {
`

var plainStyles = css`
:host {
padding: .5rem .75rem;
font-size: .75rem;
background-color: transparent;
color: var(--color-neutral-40);
}
.plain:hover,
.plain:focus {
:host:hover,
:host:focus {
color: var(--color-neutral-70);
}
`

module.exports = (props, click) => {
if (typeof click === 'function') props.click = click

var child
if (props.icon) {
child = html`
<div class="btn-wrapper">
${icon({
id: props.icon
})}
<span class="btn-text ml1">${props.text}</span>
</div>`
plainButton.green = greenButton
plainButton.icon = iconButton
plainButton.red = redButton
module.exports = plainButton

// States:
// - Text only
// - Text and icon
function buttonElement (innerText, opts) {
if (!opts) {
opts = innerText
innerText = ''
}

var icon = opts.icon
var innerHTML = null

if (innerText && !icon) {
innerHTML = html`
<div class="btn-inner-wrapper">
<span class="btn-text">${innerText}</span>
</div>
`
} else {
child = html`
<div class="btn-wrapper">
<span class="btn-text">${props.text}</span>
</div>`
innerHTML = html`
<div class="btn-inner-wrapper">
${icon}
<span class="btn-text ml1">${innerText}</span>
</div>
`
}

var defaultProps = {
'aria-label': innerText,
'title': innerText
}

var buttonProps = xtend(defaultProps, opts)
buttonProps.class = 'pointer ' + baseStyles + ' ' + buttonProps.class

return html`
<button
onclick=${props.click}
class="pointer ${prefix} ${props.style || ''} ${props.cls || ''}"
title=${props.title || props.text}
aria-label=${props.ariaLabel || props.text}
>
${child}
<button ${buttonProps}>
${innerHTML}
</button>
`
}

// - Icon only
function iconButton (innerText, opts) {
assert.equal(typeof innerText, 'string', 'elements/button: innerText should by type string')
assert.ok(innerText.length, 'elements/button: innerText should have a length >= 0')
assert.equal(typeof opts, 'object', 'elements/button: opts should by type object')
assert.ok(opts.icon, 'elements/button: opts.icon should exist')

var icon = opts.icon
opts.class = (opts.class)
? plainStyles + ' ' + opts.class
: plainStyles

var innerHTML = html`
<div class="btn-inner-wrapper">
${icon}
</div>
`

var defaultProps = {
'aria-label': innerText,
'title': innerText
}

var buttonProps = xtend(defaultProps, opts)
buttonProps.class = 'pointer ' + baseStyles + ' ' + buttonProps.class

return html`
<button ${buttonProps}>
${innerHTML}
</button>
`
}

function greenButton (innerText, opts) {
if (!opts) {
opts = innerText
innerText = ''
}

opts = opts || {}
opts.class = (opts.class) ? greenStyles + ' ' + opts.class : greenStyles
return buttonElement(innerText, opts)
}

function redButton (innerText, opts) {
if (!opts) {
opts = innerText
innerText = ''
}

opts = opts || {}
opts.class = (opts.class) ? redStyles + ' ' + opts.class : redStyles
return buttonElement(innerText, opts)
}

function plainButton (innerText, opts) {
if (!opts) {
opts = innerText
innerText = ''
}

opts = opts || {}
opts.class = (opts.class) ? plainStyles + ' ' + opts.class : plainStyles
return buttonElement(innerText, opts)
}
18 changes: 7 additions & 11 deletions elements/confirm-modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,14 @@ function createWidget () {
function render (cb) {
assert.equal(typeof cb, 'function', 'elements/confirm-modal: cb should be a function')

var deleteButton = button({
text: 'Yes, Remove Dat',
style: 'filled-green',
cls: 'fr ml3',
click: ondelete
var deleteButton = button.green('Yes, Remove Dat', {
class: 'fr ml3',
onclick: ondelete
})

var exitButton = button({
text: 'No, Cancel',
style: 'plain',
cls: 'fr',
click: onexit
var exitButton = button('No, Cancel', {
class: 'fr',
onclick: onexit
})

return html`
Expand All @@ -78,7 +74,7 @@ function createWidget () {
onclick=${onexit}
class="absolute pointer pa0 top-0 right-0 h2 w2 bg-transparent tc exit"
aria-label="Close Modal">
${icon({id: 'cross'})}
${icon('cross')}
</button>
</section>
`
Expand Down
24 changes: 9 additions & 15 deletions elements/crash-modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,9 @@ function createWidget () {
possible.
</p>
<p>
${button({
text: 'Exit Application',
style: 'filled-green',
cls: 'fr ml3',
click: onexit
${button.green('Exit Application', {
class: 'fr ml3',
onclick: onexit
})}
</p>
</section>
Expand All @@ -67,17 +65,13 @@ function createWidget () {
be reversed.
</p>
<p>
${button({
text: 'Clear Database & exit',
style: 'filled-red',
cls: 'fr ml3',
click: clearDatabase
${button.red('Clear Database & exit', {
class: 'fr ml3',
onclick: clearDatabase
})}
${button({
text: 'Delete All Data & exit',
style: 'filled-red',
cls: 'fr ml3',
click: deleteData
${button.red('Delete All Data & exit', {
class: 'fr ml3',
onclick: deleteData
})}
</p>
</section>
Expand Down
7 changes: 1 addition & 6 deletions elements/dat-import.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,14 @@ function datImportElement (props) {

assert.equal(typeof onsubmit, 'function', 'dat-import: onsubmit should be type function')

const linkIcon = icon({
id: 'link',
cls: 'absolute top-0 bottom-0 left-0'
})

return html`
<label for="dat-import" class="relative dib pa0 b--none ${prefix}">
<input name="dat-import"
type="text"
placeholder="Import dat"
onkeydown=${onKeyDown}
class="input-reset">
${linkIcon}
${icon('link', { class: 'absolute top-0 bottom-0 left-0' })}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about this syntax?

icon('#link.absolute.top-0.bottom-0.left-0')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I kinda like that; very close to hyperscript's class / id shorthand - I think having that at some point would definitely make sense. Nice ✨

I'd probably make sure there'd be full consistency with hyperscript tho:

icon('link.absolute.top-0.bottom-0.left-0#some-id')

but yeah that's nit picking. I like it!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like having the 'class' dict, it also is just as simple and already works.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah nah, agree - this would only work for icons right now; buttons is harder - gonna leave this for a bit

</label>
`

Expand Down
8 changes: 3 additions & 5 deletions elements/error-modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ function createWidget () {
})

function render (message, onexit) {
var exitButton = button({
text: 'Ok',
style: 'filled-green',
cls: 'fr ml3',
click: onexit
var exitButton = button.green('Ok', {
class: 'fr ml3',
onclick: onexit
})

return html`
Expand Down
23 changes: 10 additions & 13 deletions elements/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
const html = require('choo/html')
const assert = require('assert')
const css = require('sheetify')

const button = require('./button')
const datImport = require('./dat-import')
const icon = require('./icon')

module.exports = headerElement

Expand Down Expand Up @@ -76,22 +78,17 @@ function headerElement (props) {

var importButton = datImport({ onsubmit: onimport })

var createButton = button({
icon: 'create-new-dat',
text: 'Create New Dat',
cls: 'ml2 b--transparent header-action header-action-no-border',
click: oncreate
var createButton = button('Create New Dat', {
icon: icon('create-new-dat'),
class: 'ml2 b--transparent header-action header-action-no-border',
onclick: oncreate
})

var loginButton = button({
text: 'Log In',
cls: 'ml2 header-action log-in-button'
})
var loginButton = button('Log In', { class: 'ml2 header-action log-in-button' })

var menuButton = button({
icon: 'menu',
text: '',
cls: 'ml2 header-action header-action-no-border menu-trigger'
var menuButton = button.icon('Open Menu', {
icon: icon('menu'),
class: 'ml2 header-action header-action-no-border menu-trigger'
})

return html`
Expand Down
Loading