Pinafore-Web-Client-Frontend/src/routes/_components/IconButton.html

175 lines
5.0 KiB
HTML
Raw Normal View History

<!-- Normally "pressable" icons would be toggle buttons, but to avoid having the titles and labels mismatched
due to guidelines from http://w3c.github.io/aria-practices/#button , we just use normal buttons and change
the aria-label instead. See discussion in: https://github.com/nolanlawson/pinafore/issues/1633 -->
<button id={elementId}
type="button"
title={ariaLabel}
aria-label={ariaLabel}
aria-hidden={ariaHidden ? 'true' : undefined}
tabindex={ariaHidden ? '-1' : '0'}
class={computedClass}
{disabled}
ref:node
>
<SvgIcon className="icon-button-svg {svgClassName || ''}" ref:svg {href} />
{#if checked}
<SvgIcon className="icon-button-svg icon-button-check" ref:check href="#fa-check" />
{/if}
</button>
2018-01-28 21:51:48 +01:00
<style>
.icon-button {
position: relative;
2018-01-28 21:51:48 +01:00
padding: 6px 10px;
background: none;
border: none;
2018-04-05 06:45:19 +02:00
display: flex;
align-items: center;
justify-content: center;
pointer-events: auto;
2018-01-28 21:51:48 +01:00
}
:global(.icon-button-svg) {
2018-01-28 21:51:48 +01:00
width: 24px;
height: 24px;
fill: var(--action-button-fill-color);
2018-03-23 04:09:20 +01:00
pointer-events: none; /* hack for Edge */
2018-01-28 21:51:48 +01:00
}
:global(.icon-button-check) {
position: absolute;
top: 1px;
right: 2px;
height: 12px;
width: 12px;
}
:global(.icon-button.big-icon .icon-button-svg) {
2018-01-28 21:51:48 +01:00
width: 32px;
height: 32px;
}
2018-04-05 06:45:19 +02:00
/*
* regular styles
*/
:global(.icon-button:hover .icon-button-svg) {
2018-01-28 21:51:48 +01:00
fill: var(--action-button-fill-color-hover);
}
:global(.icon-button.not-pressable:active .icon-button-svg,
.icon-button.same-pressed:active .icon-button-svg) {
2018-01-28 21:51:48 +01:00
fill: var(--action-button-fill-color-active);
}
:global(.icon-button.pressed.not-same-pressed .icon-button-svg) {
2018-03-21 17:38:20 +01:00
fill: var(--action-button-fill-color-pressed);
2018-01-28 21:51:48 +01:00
}
:global(.icon-button.pressed.not-same-pressed:hover .icon-button-svg) {
2018-01-28 21:51:48 +01:00
fill: var(--action-button-fill-color-pressed-hover);
}
:global(.icon-button.pressed.not-same-pressed:active .icon-button-svg) {
2018-01-28 21:51:48 +01:00
fill: var(--action-button-fill-color-pressed-active);
}
2018-04-05 06:45:19 +02:00
/*
* muted
*/
:global(.icon-button.muted-style .icon-button-svg) {
2018-04-05 06:45:19 +02:00
fill: var(--action-button-deemphasized-fill-color);
}
:global(.icon-button.muted-style:hover .icon-button-svg) {
2018-04-05 06:45:19 +02:00
fill: var(--action-button-deemphasized-fill-color-hover);
}
:global(.icon-button.muted-style.not-pressable:active .icon-button-svg,
.icon-button.muted-style.same-pressed:active .icon-button-svg) {
2018-04-05 06:45:19 +02:00
fill: var(--action-button-deemphasized-fill-color-active);
}
:global(.icon-button.muted-style.pressed.not-same-pressed .icon-button-svg) {
2018-04-05 06:45:19 +02:00
fill: var(--action-button-deemphasized-fill-color-pressed);
}
:global(.icon-button.muted-style.pressed.not-same-pressed:hover .icon-button-svg) {
2018-04-05 06:45:19 +02:00
fill: var(--action-button-deemphasized-fill-color-pressed-hover);
}
:global(.icon-button.muted-style.pressed.not-same-pressed:active .icon-button-svg) {
2018-04-05 06:45:19 +02:00
fill: var(--action-button-deemphasized-fill-color-pressed-active);
}
2018-02-24 23:49:28 +01:00
</style>
<script>
import { classname } from '../_utils/classname.js'
import { store } from '../_store/store.js'
import SvgIcon from './SvgIcon.html'
2018-03-15 02:52:33 +01:00
2018-02-24 23:49:28 +01:00
export default {
oncreate () {
const { clickListener } = this.get()
if (clickListener) {
this.onClick = this.onClick.bind(this)
this.refs.node.addEventListener('click', this.onClick)
}
if (process.env.NODE_ENV !== 'production') {
const { pressable, pressedLabel, label } = this.get()
if (pressable && ((!pressedLabel || !label) || pressedLabel === label)) {
throw new Error('pressable buttons should have a label and a pressedLabel different from each other')
}
}
},
ondestroy () {
2019-08-03 22:49:37 +02:00
const { clickListener } = this.get()
if (clickListener) {
this.refs.node.removeEventListener('click', this.onClick)
}
},
data: () => ({
big: false,
muted: false,
disabled: false,
2019-08-20 04:08:59 +02:00
svgClassName: undefined,
elementId: '',
pressable: false,
pressed: false,
pressedLabel: undefined,
2019-08-20 04:08:59 +02:00
className: undefined,
sameColorWhenPressed: false,
ariaHidden: false,
clickListener: true,
checked: false
}),
2018-03-23 04:23:00 +01:00
store: () => store,
2018-02-24 23:49:28 +01:00
computed: {
computedClass: ({ pressable, pressed, big, muted, sameColorWhenPressed, className }) => (classname(
'icon-button',
!pressable && 'not-pressable',
pressed && 'pressed',
big && 'big-icon',
muted && 'muted-style',
sameColorWhenPressed ? 'same-pressed' : 'not-same-pressed',
className
)),
ariaLabel: ({ pressable, pressed, label, pressedLabel }) => ((pressable && pressed) ? pressedLabel : label)
2018-04-21 17:32:40 +02:00
},
methods: {
animate (animation, checkmarkAnimation) {
this.refs.svg.animate(animation)
if (checkmarkAnimation && this.get().checked) {
this.refs.check.animate(checkmarkAnimation)
}
},
onClick (e) {
this.fire('click', e)
2018-04-21 17:32:40 +02:00
}
},
components: {
SvgIcon
2018-02-24 23:49:28 +01:00
}
}
</script>