: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

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%); } } } }