forked from Bitmessage/virtpool
674 lines
21 KiB
SCSS
674 lines
21 KiB
SCSS
:root {
|
|
--tagify-dd-color-primary: rgb(53,149,246); // should be same as "$tags-focus-border-color"
|
|
--tagify-dd-bg-color: white;
|
|
}
|
|
|
|
.tagify{
|
|
// SCSS "default" allows overriding variables BEFORE they are set in the below lines of code
|
|
$self: &;
|
|
$tags-border-color : #DDD !default;
|
|
$tags-hover-border-color : #CCC !default;
|
|
$tags-focus-border-color : #3595f6 !default;
|
|
$tagMargin : 5px !default;
|
|
$tag-pad : .3em .5em !default;
|
|
$tag-min-width : 1ch !default;
|
|
$tag-max-width : auto !default;
|
|
$tag-text-color : black !default;
|
|
$tag-text-color--edit : black !default;
|
|
$tag-bg : #E5E5E5 !default;
|
|
$tag-hover : #D3E2E2 !default;
|
|
$tag-remove : #D39494 !default;
|
|
$tag-remove-btn-color : $tag-text-color !default;
|
|
$tag-remove-btn-bg : none !default;
|
|
$tag-remove-btn-bg--hover: darken($tag-remove, 8) !default;
|
|
$tag-invalid-color : $tag-remove !default;
|
|
$tag-invalid-bg : rgba($tag-remove, .5) !default;
|
|
$tag-inset-shadow-size : 1.1em !default;
|
|
$tag-hide-transition : .3s !default;
|
|
$placeholder-color : rgba($tag-text-color, .4) !default;
|
|
$placeholder-color-focus : rgba($tag-text-color, .25) !default;
|
|
$input-color : inherit !default;
|
|
$tagify-dd-bg-color : white !default;
|
|
$tagify-dd-color-primary : rgb(53,149,246) !default;
|
|
|
|
// CSS variables
|
|
--tags-border-color : #{$tags-border-color};
|
|
--tags-hover-border-color : #{$tags-hover-border-color};
|
|
--tags-focus-border-color : #{$tags-focus-border-color};
|
|
--tag-bg : #{$tag-bg};
|
|
--tag-hover : #{$tag-hover};
|
|
--tag-text-color : #{$tag-text-color};
|
|
--tag-text-color--edit : #{$tag-text-color--edit};
|
|
--tag-pad : #{$tag-pad};
|
|
--tag-inset-shadow-size : #{$tag-inset-shadow-size};
|
|
--tag-invalid-color : #{$tag-invalid-color};
|
|
--tag-invalid-bg : #{$tag-invalid-bg};
|
|
--tag-remove-bg : #{rgba($tag-remove, .3)};
|
|
--tag-remove-btn-color : #{$tag-remove-btn-color};
|
|
--tag-remove-btn-bg : #{$tag-remove-btn-bg};
|
|
--tag-remove-btn-bg--hover : #{$tag-remove-btn-bg--hover};
|
|
--input-color : #{$input-color};
|
|
--tag--min-width : #{$tag-min-width};
|
|
--tag--max-width : #{$tag-max-width};
|
|
--tag-hide-transition : #{$tag-hide-transition};
|
|
--placeholder-color : #{$placeholder-color};
|
|
--placeholder-color-focus : #{$placeholder-color-focus};
|
|
--loader-size : .8em;
|
|
|
|
@mixin firefox {
|
|
@at-root {
|
|
@-moz-document url-prefix() {
|
|
& { @content; }
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin placeholder( $show:true ){
|
|
transition: .2s ease-out;
|
|
|
|
@if $show == true {
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
@else {
|
|
opacity: 0;
|
|
transform: translatex(6px);
|
|
}
|
|
}
|
|
|
|
@mixin loader(){
|
|
content: '';
|
|
vertical-align: middle;
|
|
opacity: 1;
|
|
width: .7em;
|
|
height: .7em;
|
|
width: var(--loader-size);
|
|
height: var(--loader-size);
|
|
border: 3px solid;
|
|
border-color: #EEE #BBB #888 transparent;
|
|
border-radius: 50%;
|
|
animation: rotateLoader .4s infinite linear;
|
|
}
|
|
|
|
@mixin tagReadonlyBG{
|
|
background: linear-gradient(45deg, var(--tag-bg) 25%,
|
|
transparent 25%,
|
|
transparent 50%,
|
|
var(--tag-bg) 50%,
|
|
var(--tag-bg) 75%,
|
|
transparent 75%,
|
|
transparent) 0/5px 5px;
|
|
box-shadow: none;
|
|
filter: brightness(.95);
|
|
}
|
|
|
|
@keyframes tags--bump{
|
|
30% { transform: scale(1.2); }
|
|
}
|
|
|
|
@keyframes rotateLoader {
|
|
to{ transform: rotate(1turn) }
|
|
}
|
|
|
|
display : flex;
|
|
align-items : flex-start;
|
|
flex-wrap : wrap;
|
|
border : 1px solid $tags-border-color;
|
|
border : 1px solid var(--tags-border-color);
|
|
padding : 0;
|
|
line-height : 1.1;
|
|
cursor : text;
|
|
outline : none;
|
|
position : relative;
|
|
box-sizing : border-box;
|
|
transition : .1s;
|
|
|
|
&:hover{
|
|
border-color: $tags-hover-border-color;
|
|
border-color: var(--tags-hover-border-color);
|
|
}
|
|
|
|
&.tagify--focus{
|
|
transition: 0s;
|
|
border-color: $tags-focus-border-color;
|
|
border-color: var(--tags-focus-border-color);
|
|
}
|
|
|
|
// Global "read-only" mode (no input button)
|
|
&[readonly]{
|
|
&:not(.tagify--mix){
|
|
cursor: default;
|
|
> #{ $self }__input{
|
|
visibility: hidden;
|
|
width: 0;
|
|
margin: $tagMargin 0;
|
|
}
|
|
|
|
#{ $self }__tag > div{
|
|
padding: $tag-pad;
|
|
padding: var(--tag-pad);
|
|
&::before{
|
|
@include tagReadonlyBG;
|
|
}
|
|
}
|
|
}
|
|
|
|
#{ $self }__tag__removeBtn{ display:none; }
|
|
|
|
}
|
|
|
|
&--loading{
|
|
#{ $self }__input{
|
|
&::before{ content:none; }
|
|
&::after{
|
|
@include loader;
|
|
margin: -2px 0 -2px .5em;
|
|
}
|
|
&:empty{
|
|
&::after{
|
|
margin-left:0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////
|
|
// Hides originals
|
|
+ input,
|
|
+ textarea{ display:none !important; }
|
|
|
|
&__tag{
|
|
display : inline-flex;
|
|
align-items: center;
|
|
margin : $tagMargin 0 $tagMargin $tagMargin;
|
|
position : relative;
|
|
z-index : 1;
|
|
outline : none;
|
|
cursor : default;
|
|
transition : .13s ease-out;
|
|
|
|
> div{ // :not([contenteditable])
|
|
vertical-align : top;
|
|
box-sizing : border-box;
|
|
max-width : 100%;
|
|
padding : $tag-pad;
|
|
padding : var(--tag-pad, $tag-pad);
|
|
color : $tag-text-color;
|
|
color : var(--tag-text-color, $tag-text-color);
|
|
line-height : inherit;
|
|
border-radius : 3px;
|
|
// user-select : none; // should allow selecting text if the user wishes to copy something
|
|
white-space : nowrap;
|
|
transition : .13s ease-out;
|
|
|
|
> *{
|
|
white-space : pre-wrap;
|
|
overflow : hidden;
|
|
text-overflow : ellipsis;
|
|
display : inline-block;
|
|
vertical-align : top;
|
|
min-width : $tag-min-width;
|
|
max-width : $tag-max-width;
|
|
min-width : var(--tag--min-width, $tag-min-width);
|
|
max-width : var(--tag--max-width, $tag-max-width);
|
|
transition : .8s ease, .1s color;
|
|
|
|
|
|
&[contenteditable]{
|
|
outline: none;
|
|
user-select: text;
|
|
cursor: text;
|
|
// fix: sometimes the caret after the last character wasn't visible (when setting {backspace:"edit"})
|
|
margin: -2px;
|
|
padding: 2px;
|
|
max-width: 350px;
|
|
}
|
|
}
|
|
|
|
&::before{
|
|
content: '';
|
|
position: absolute;
|
|
border-radius: inherit;
|
|
left:0; top:0; right:0; bottom:0;
|
|
z-index: -1;
|
|
pointer-events:none;
|
|
transition: 120ms ease;
|
|
animation : tags--bump .3s ease-out 1;
|
|
|
|
box-shadow: 0 0 0 $tag-inset-shadow-size $tag-bg inset;
|
|
box-shadow: 0 0 0 var(--tag-inset-shadow-size, $tag-inset-shadow-size) var(--tag-bg, $tag-bg) inset;
|
|
}
|
|
}
|
|
|
|
&:hover:not([readonly]){
|
|
div{ // :not([contenteditable])
|
|
&::before{
|
|
$size: -$tagMargin/2;
|
|
$size: -2px;
|
|
top:$size; right:$size; bottom:$size; left:$size;
|
|
box-shadow: 0 0 0 $tag-inset-shadow-size $tag-hover inset;
|
|
box-shadow: 0 0 0 var(--tag-inset-shadow-size, $tag-inset-shadow-size) var(--tag-hover, $tag-hover) inset;
|
|
// box-shadow: 0 0 0 0 $tag-remove inset
|
|
}
|
|
// background:nth($tagColor,2);
|
|
//background:none;
|
|
// box-shadow: 0 0 0 2px $tag-hover inset;
|
|
// transition:50ms;
|
|
}
|
|
}
|
|
|
|
&--loading{
|
|
pointer-events: none;
|
|
|
|
.tagify__tag__removeBtn{
|
|
display: none;
|
|
}
|
|
|
|
&::after{
|
|
--loader-size: .4em;
|
|
@include loader;
|
|
margin: 0 .5em 0 -.1em;
|
|
}
|
|
}
|
|
|
|
&--flash{
|
|
div::before{ animation:none; }
|
|
}
|
|
|
|
&--hide{
|
|
width : 0 !important;
|
|
padding-left : 0;
|
|
padding-right : 0;
|
|
margin-left : 0;
|
|
margin-right : 0;
|
|
opacity : 0;
|
|
transform : scale(0);
|
|
transition : $tag-hide-transition;
|
|
transition : var(--tag-hide-transition, $tag-hide-transition);
|
|
pointer-events : none;
|
|
|
|
> div > *{
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
|
|
&#{ $self }{
|
|
&--noAnim{
|
|
> div::before{
|
|
animation:none;
|
|
}
|
|
}
|
|
|
|
&--notAllowed:not(.tagify__tag--editable){
|
|
div{
|
|
> span{ opacity:.5; } // filter:blur(.2px);
|
|
&::before{
|
|
box-shadow: 0 0 0 $tag-inset-shadow-size $tag-invalid-bg inset !important;
|
|
box-shadow: 0 0 0 var(--tag-inset-shadow-size, $tag-inset-shadow-size) var(--tag-invalid-bg, $tag-invalid-bg) inset !important;
|
|
transition: .2s;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
&[readonly]{
|
|
#{ $self }__tag__removeBtn{ display:none; }
|
|
> div{// padding: $tag-pad;
|
|
&::before{
|
|
@include tagReadonlyBG;
|
|
}
|
|
}
|
|
}
|
|
|
|
&--editable{
|
|
> div{
|
|
color : $tag-text-color--edit;
|
|
color : var(--tag-text-color--edit, $tag-text-color--edit);
|
|
|
|
&::before{
|
|
box-shadow: 0 0 0 2px $tag-hover inset !important;
|
|
box-shadow: 0 0 0 2px var(--tag-hover, $tag-hover) inset !important;
|
|
}
|
|
}
|
|
|
|
> #{$self}__tag__removeBtn{
|
|
pointer-events: none;
|
|
|
|
&::after{
|
|
opacity: 0;
|
|
transform: translateX(100%) translateX(5px);
|
|
}
|
|
}
|
|
|
|
&.tagify--invalid{
|
|
> div{
|
|
&::before{
|
|
box-shadow: 0 0 0 2px $tag-invalid-color inset !important;
|
|
box-shadow: 0 0 0 2px var(--tag-invalid-color, $tag-invalid-color) inset !important;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
&__removeBtn{
|
|
$size: 14px;
|
|
|
|
order : 5;
|
|
display : inline-flex;
|
|
align-items : center;
|
|
justify-content: center;
|
|
border-radius : 50px;
|
|
cursor : pointer;
|
|
font : #{$size}/1 Arial;
|
|
background : $tag-remove-btn-bg;
|
|
background : var(--tag-remove-btn-bg, $tag-remove-btn-bg);
|
|
color : $tag-remove-btn-color;
|
|
color : var(--tag-remove-btn-color, $tag-remove-btn-color);
|
|
|
|
width : $size;
|
|
height : $size;
|
|
margin-right : $size/3;
|
|
margin-left : -$size/3;
|
|
|
|
overflow : hidden;
|
|
transition : .2s ease-out;
|
|
|
|
&::after{
|
|
content: "\00D7";
|
|
transition: .3s, color 0s;
|
|
}
|
|
|
|
&:hover{
|
|
color: white;
|
|
background: $tag-remove-btn-bg--hover;
|
|
background: var(--tag-remove-btn-bg--hover, $tag-remove-btn-bg--hover);
|
|
// + span{ box-shadow: 0 0 0 2px $tag-remove inset; transition:.2s; }
|
|
+ div{
|
|
> span{ opacity:.5; } // filter:blur(.2px);
|
|
&::before{
|
|
box-shadow: 0 0 0 $tag-inset-shadow-size rgba($tag-remove, .3) inset !important;
|
|
box-shadow: 0 0 0 var(--tag-inset-shadow-size, $tag-inset-shadow-size) var(--tag-remove-bg, rgba($tag-remove, .3)) inset !important;
|
|
transition: box-shadow .2s;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
&:not(#{$self}--mix){
|
|
#{ $self }__input{
|
|
// https://stackoverflow.com/a/13470210/104380
|
|
br { display:none; }
|
|
* { display:inline; white-space:nowrap; }
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////
|
|
// Holds the placeholder & the tags input
|
|
&__input{
|
|
$placeholder-width : 110px;
|
|
flex-grow: 1;
|
|
display: inline-block;
|
|
min-width: $placeholder-width;
|
|
margin: $tagMargin;
|
|
padding: $tag-pad;
|
|
padding: var(--tag-pad, $tag-pad);
|
|
line-height: inherit;
|
|
position: relative;
|
|
white-space: pre-wrap; // #160 Line break (\n) as delimeter
|
|
color: $input-color;
|
|
color: var(--input-color, $input-color);
|
|
box-sizing: inherit;
|
|
|
|
&:empty{
|
|
@include firefox {
|
|
// clicking twice on the input (not fast) disallows typing (bug) only when the input has "display:flex".
|
|
// disabled the below rule for the above reason:
|
|
// display: flex; // https://bugzilla.mozilla.org/show_bug.cgi?id=904846#c45
|
|
}
|
|
|
|
&::before{
|
|
@include placeholder;
|
|
display: inline-block;
|
|
width: auto;
|
|
|
|
#{ $self }--mix &{
|
|
display: inline-block;
|
|
}
|
|
}
|
|
}
|
|
|
|
&:focus{
|
|
outline:none;
|
|
|
|
&::before{
|
|
@include placeholder(false);
|
|
|
|
/* ALL MS BROWSERS: hide placeholder (on focus) otherwise the caret is places after it, which is weird */
|
|
/* IE10+ CSS styles go here */
|
|
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
|
display: none;
|
|
}
|
|
/* IE Edge 12+ CSS styles go here */
|
|
@supports ( -ms-ime-align:auto ) {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
&:empty{
|
|
&::before{
|
|
@include placeholder(true);
|
|
|
|
// Seems to be fixed! no need for the below hack
|
|
// @include firefox {
|
|
// // remove ":after" pseudo element: https://bugzilla.mozilla.org/show_bug.cgi?id=904846#c45
|
|
// content: unset;
|
|
// // display:inline-block;
|
|
// }
|
|
|
|
color: $placeholder-color-focus;
|
|
color: var(--placeholder-color-focus);
|
|
}
|
|
|
|
&::after{
|
|
@include firefox {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
&::before{
|
|
content: attr(data-placeholder);
|
|
height: 1em;
|
|
line-height: 1em;
|
|
margin: auto 0;
|
|
z-index: 1;
|
|
color: $placeholder-color;
|
|
color: var(--placeholder-color);
|
|
white-space: nowrap;
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
position: absolute;
|
|
|
|
#{$self}--mix &{
|
|
display: none;
|
|
position: static;
|
|
line-height: inherit;
|
|
}
|
|
}
|
|
/* Seems firefox newer versions don't need this any more
|
|
@supports ( -moz-appearance:none ){
|
|
&::before{
|
|
line-height: inherit;
|
|
position:relative;
|
|
}
|
|
}
|
|
*/
|
|
// tries to suggest the rest of the value from the first item in the whitelist which matches it
|
|
&::after{
|
|
content: attr(data-suggest);
|
|
display: inline-block;
|
|
white-space: pre; /* allows spaces at the beginning */
|
|
color: $tag-text-color;
|
|
opacity: .3;
|
|
pointer-events:none;
|
|
max-width: 100px;
|
|
}
|
|
|
|
// &--invalid{
|
|
// // color: $invalid-input-color;
|
|
// }
|
|
|
|
/*
|
|
in "mix mode" the tags are inside the "input" element
|
|
*/
|
|
#{ $self }__tag{
|
|
margin: 0; // a developer can choose to have automatic horizontal margin ("1ch" advised) between tags or use manual keyboard spaces
|
|
// line-height: 1.1;
|
|
|
|
> div{
|
|
padding-top:0; padding-bottom:0;
|
|
}
|
|
}
|
|
}
|
|
|
|
&--mix {
|
|
display: block; // display:flex makes Chrome generates <div><br></div> when pressing ENTER key
|
|
|
|
#{ $self }__input{
|
|
padding: $tagMargin;
|
|
margin: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
line-height: 1.5;
|
|
|
|
&::before{ height:auto; }
|
|
|
|
// no suggested-complete are shown in mix-mode while higilighting dropdown options
|
|
&::after{ content:none; }
|
|
}
|
|
}
|
|
|
|
&--select{
|
|
&::after{
|
|
$size: 16px;
|
|
content: '>';
|
|
opacity: .5;
|
|
position: absolute;
|
|
top: 50%;
|
|
right: 0;
|
|
bottom: 0;
|
|
font: $size monospace;
|
|
line-height: $size/2;
|
|
height: $size/2;
|
|
pointer-events: none;
|
|
transform: translate(-150%, -50%) scaleX(1.2) rotate(90deg);
|
|
transition: .2s ease-in-out;
|
|
}
|
|
|
|
&[aria-expanded=true]{
|
|
&::after{
|
|
transform: translate(-150%, -50%) rotate(270deg) scaleY(1.2);
|
|
}
|
|
}
|
|
|
|
#{$self}__tag{
|
|
position: absolute;
|
|
top: 0;
|
|
right: 1.8em;
|
|
bottom: 0;
|
|
div{
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
#{$self}__input{
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
&--invalid{
|
|
--tags-border-color : #{$tag-invalid-color};
|
|
}
|
|
|
|
// Since the dropdown is an external element, which is positioned directly on the body element
|
|
// it cannot ingerit the CSS variables applied on the ".Tagify" element
|
|
&__dropdown{
|
|
$dropdown: &;
|
|
$trans: .25s cubic-bezier(0,1,.5,1);
|
|
position: absolute;
|
|
z-index: 9999;
|
|
transform: translateY(1px);
|
|
overflow: hidden;
|
|
|
|
&[placement="top"]{
|
|
margin-top: 0;
|
|
transform: translateY(-100%);
|
|
#{$dropdown}__wrapper{
|
|
border-top-width: 1px;
|
|
border-bottom-width: 0;
|
|
}
|
|
}
|
|
|
|
// when the dropdown shows next to the caret while typing
|
|
&[position="text"]{
|
|
box-shadow: 0 0 0 3px rgba(var(--tagify-dd-color-primary), .1);
|
|
font-size: .9em;
|
|
#{$dropdown}__wrapper{
|
|
border-width: 1px;
|
|
}
|
|
}
|
|
|
|
&__wrapper{
|
|
max-height: 300px;
|
|
overflow: hidden;
|
|
background: $tagify-dd-bg-color;
|
|
background: var(--tagify-dd-bg-color);
|
|
border: 1px solid $tags-focus-border-color;
|
|
border-color: var(--tagify-dd-color-primary);
|
|
border-top-width: 0;
|
|
box-shadow: 0 2px 4px -2px rgba(black,.2);
|
|
// box-sizing: border-box;
|
|
transition: $trans;
|
|
|
|
&:hover{
|
|
overflow: auto;
|
|
}
|
|
}
|
|
|
|
// intial state, pre-rendered
|
|
&--initial{
|
|
#{$dropdown}__wrapper{
|
|
max-height: 20px;
|
|
transform: translateY(-1em);
|
|
}
|
|
|
|
&[placement="top"]{
|
|
#{$dropdown}__wrapper{
|
|
transform: translateY(2em);
|
|
}
|
|
}
|
|
}
|
|
|
|
&__item{
|
|
box-sizing: inherit;
|
|
padding: $tag-pad;
|
|
margin: 1px;
|
|
cursor: pointer;
|
|
border-radius: 2px;
|
|
position: relative;
|
|
outline: none;
|
|
|
|
&--active{
|
|
background: $tagify-dd-color-primary;
|
|
background: var(--tagify-dd-color-primary);
|
|
color: white;
|
|
}
|
|
&:active{
|
|
filter: brightness(105%);
|
|
}
|
|
}
|
|
}
|
|
} |