shentao / vue-multiselect

Universal select/multiselect/tagging component for Vue.js
https://vue-multiselect.js.org/
MIT License
6.68k stars 989 forks source link

Customize styles through sass variables? #420

Open projct1 opened 7 years ago

shentao commented 7 years ago

You can provide your own stylesheets. There is no way of modifying the current styles using Sass variables. No plans to implement that either. Sorry. :(

projct1 commented 7 years ago

😭 Very inconvenient overwrite all styles for each blocks... ☹️

shentao commented 7 years ago

You can also override selected classes.

jeremykenedy commented 7 years ago

Just curious why this is not in the plans? Did you want it to be but resources are constrained?

jeremykenedy commented 7 years ago

@rorc

$color1: #ffffff
$color2: #41B883
$color3: #35495E
$color4: #E8E8E8
$color5: #999999
$color6: #ADADAD
$color7: #F3F3F3
$color8: #FF6A6A

$spinnerBg: $color1
$spinnerBorderColor: $color2
$multiselectColor: $color3
$multiselectBg: $color1
$multiselectBorderColorHover: darken($color4, 10%)
$multiselectBorderColorFocus: darken($color4, 25%)
$multiselectTagsBgColor: $color1
$multiselectTagsBorder: 1px solid $color4
$multiselectTagColor: $color1
$multiselectTagBgColor: $color2
$multiselectTagIconColor: darken($color2, 20%)
$multiselectTagIconColorHover: darken($color2, 8%)
$multiselectTagIconColorBgHover: $color1
$multiselectCurrentBorderColor: $color4
$multiselectBorderColor: $color5
$multiselectColor: $color5
$multiselectPlaceholderColor: $color6
$multiselectContentBgColor: $color1
$multiselectContentBorderColor: $color4
$multiselectOptionHighlightBgColor: $color2
$multiselectOptionHighlightColor: $color1
$multiselectOptionSelectedBgColor: $color7
$multiselectOptionSelectedColor: $color3
$multiselectOptionHighlightSelectedBgColor: $color8
$multiselectOptionHighlightSelectedColor: $color1
$multiselectDisabledBgColor: darken($color1, 7%)
$multiselectDisabledColor: darken($color1, 35%)
$multiselectDisabledOptionBgColor: darken($color2, 3%)

$multiselectTagIcon: "\00D7"
$multiselectTagsBorderRadius: 0.3125rem

.multiselect__spinner
  position: absolute
  right: 1px
  top: 1px
  width: 3rem
  height: 2.1875rem
  background: $spinnerBg
  display: block

  &:before,
  &:after
    position: absolute
    content: ''
    top: 50%
    left: 50%
    margin: 0.875rem 0 0 0.875rem
    width: 1rem
    height: 1rem
    border-radius: 100%
    border-color: $spinnerBorderColor transparent transparent
    border-style: solid
    border-width: 2px
    box-shadow: 0 0 0 1px transparent

  &:before
    animation: spinning 2.4s cubic-bezier(0.41, 0.26, 0.2, 0.62)
    animation-iteration-count: infinite

  &:after
    animation: spinning 2.4s cubic-bezier(0.51, 0.09, 0.21, 0.8)
    animation-iteration-count: infinite

.multiselect__loading-transition
  transition: opacity 0.4s ease-in-out
  opacity: 1

.multiselect__loading-enter,
.multiselect__loading-leave
  opacity: 0

.multiselect,
.multiselect__input,
.multiselect__single
  font:
    family: inherit
    size: 0.875rem
    weight: lighter

.multiselect
  box-sizing: content-box

  *
    box-sizing: border-box

  display: block
  position: relative
  width: 100%
  min-height: 2.5rem
  text-align: left
  color: $multiselectColor

  &:focus
    outline: none

  &--active
    z-index: 50

    .multiselect__current,
    .multiselect__input,
    .multiselect__tags
      border-bottom-left-radius: 0
      border-bottom-right-radius: 0

    .multiselect__select
      transform: rotateZ(180deg)

.multiselect__input,
.multiselect__single
  position: relative
  display: inline-block
  min-height: 1.25rem
  line-height: 1.25rem
  border: none
  border-radius: $multiselectTagsBorderRadius
  background: $multiselectBg
  padding: 1px 0 0 0.3125rem
  width: auto
  transition: border .1s ease
  box-sizing: border-box
  margin-bottom: 0.5rem

  &:hover
    border-color: $multiselectBorderColorHover

  &:focus
    border-color: $multiselectBorderColorFocus
    outline: none

.multiselect__single
  padding-left: 0.375rem
  margin-bottom: 0.5rem

.multiselect__tags
  min-height: 2.5rem
  display: block
  padding: 0.5rem 2.5rem 0 0.5rem
  border-radius: $multiselectTagsBorderRadius
  border: $multiselectTagsBorder
  background: $multiselectTagsBgColor

.multiselect__tag
  position: relative
  display: inline-block
  padding: 0.25rem 1.625rem 0.25rem 0.625rem
  border-radius: $multiselectTagsBorderRadius
  margin-right: 0.625rem
  color: $multiselectTagColor
  line-height: 1
  background: $multiselectTagBgColor
  margin-bottom: 0.5rem

.multiselect__tag-icon
  cursor: pointer
  margin-left: 7px
  position: absolute
  right: 0
  top: 0
  bottom: 0
  font:
    weight: 700
    style: initial
  width: 1.375rem
  text-align: center
  line-height: 1.375rem
  transition: all 0.2s ease
  border-radius: $multiselectTagsBorderRadius

  &:after
    content: $multiselectTagIcon
    color: $multiselectTagIconColor
    font-size: 0.875rem

  &:focus, &:hover
    background: $multiselectTagIconColorHover

    &:after
      color: $multiselectTagIconColorBgHover

.multiselect__current
  line-height: 1rem
  min-height: 2.5rem
  box-sizing: border-box
  display: block
  overflow: hidden
  padding: 0.5rem 0.75rem 0
  padding-right: 1.875rem
  white-space: nowrap
  margin: 0
  text-decoration: none
  border-radius: $multiselectTagsBorderRadius
  border: 1px solid $multiselectCurrentBorderColor
  cursor: pointer

.multiselect__select
  line-height: 1rem
  display: block
  position: absolute
  box-sizing: border-box
  width: 2.5rem
  height: 2.375rem
  right: 1px
  top: 1px
  padding: 0.25rem 0.5rem
  margin: 0
  text-decoration: none
  text-align: center
  cursor: pointer
  transition: transform 0.2s ease

  &:before
    position: relative
    right: 0
    top: 65%
    color: $multiselectColor
    margin-top: 0.25rem
    border-style: solid
    border-width: 0.3125rem 0.3125rem 0 0.3125rem
    border-color: $multiselectBorderColor transparent transparent transparent
    content: ""

.multiselect__placeholder
  color: $multiselectPlaceholderColor
  display: inline-block
  margin-bottom: 0.625rem
  padding-top: 0.125rem

  .multiselect--active &
    display: none

.multiselect__content
  position: absolute
  list-style: none
  display: block
  background: $multiselectContentBgColor
  width: 100%
  max-height: 15rem
  overflow: auto
  padding: 0
  margin: 0
  border: 1px solid $multiselectContentBorderColor
  border-top: none
  border-bottom-left-radius: $multiselectTagsBorderRadius
  border-bottom-right-radius: $multiselectTagsBorderRadius
  z-index: 50

  &::webkit-scrollbar
    display: none

.multiselect__option
  display: block
  padding: 0.75rem
  min-height: 2.5rem
  line-height: 1rem
  font-weight: 300
  text-decoration: none
  text-transform: none
  vertical-align: middle
  position: relative
  cursor: pointer

  &:after
    top: 0
    right: 0
    position: absolute
    line-height: 2.5rem
    padding-right: 0.75rem
    padding-left: 1.25rem

  &--highlight
    background: $multiselectOptionHighlightBgColor
    outline: none
    color: $multiselectOptionHighlightColor

    &:after
      content: attr(data-select)
      color: $multiselectOptionHighlightColor

  &--selected
    background: $multiselectOptionSelectedBgColor
    color: $multiselectOptionSelectedColor
    font-weight: bold

    &:after
      content: attr(data-selected)
      font-weight: 300
      color: darken($multiselectOptionSelectedBgColor, 20%)

.multiselect__option--selected.multiselect__option--highlight
  background: $multiselectOptionHighlightSelectedBgColor
  color: $multiselectOptionHighlightSelectedColor
  font-weight: lighter

  &:after
    content: attr(data-deselect)
    color: $multiselectOptionHighlightSelectedColor

.multiselect--disabled
  background: $multiselectDisabledBgColor
  pointer-events: none

  .multiselect__current,
  .multiselect__select
    background: $multiselectDisabledBgColor
    color: $multiselectDisabledColor

.multiselect__option--disabled
  background: $multiselectDisabledBgColor
  color: $multiselectDisabledColor
  cursor: text
  pointer-events: none

  &:visited
    color: $multiselectDisabledColor

  &:hover,
  &:focus
    background: $multiselectDisabledOptionBgColor

.multiselect-transition
  transition: all .3s ease

.multiselect-enter, .multiselect-leave
  opacity: 0
  max-height: 0 !important
gfviegas commented 7 years ago

@jeremykenedy I LOVE YOU!

benjivm commented 7 years ago

@jeremykenedy just wanted to echo @gfviegas with a big thanks for the sass!

assembledadam commented 6 years ago

Thanks for the SASS - however I think it's already out of sync with the repo (or just isn't quite right) - some things were misaligned compared to using the default CSS. Turned out I didn't need to use this, so I haven't bothered to fix.

But for those it's working for, I converted it to non-indented syntax for anyone that uses that style:

$color1: #ffffff;
$color2: #41B883;
$color3: #35495E;
$color4: #E8E8E8;
$color5: #999999;
$color6: #ADADAD;
$color7: #F3F3F3;
$color8: #FF6A6A;

$spinnerBg: $color1;
$spinnerBorderColor: $color2;
$multiselectColor: $color3;
$multiselectBg: $color1;
$multiselectBorderColorHover: darken($color4, 10%);
$multiselectBorderColorFocus: darken($color4, 25%);
$multiselectTagsBgColor: $color1;
$multiselectTagsBorder: 1px solid $color4;
$multiselectTagColor: $color1;
$multiselectTagBgColor: $color2;
$multiselectTagIconColor: darken($color2, 20%);
$multiselectTagIconColorHover: darken($color2, 8%);
$multiselectTagIconColorBgHover: $color1;
$multiselectCurrentBorderColor: $color4;
$multiselectBorderColor: $color5;
$multiselectColor: $color5;
$multiselectPlaceholderColor: $color6;
$multiselectContentBgColor: $color1;
$multiselectContentBorderColor: $color4;
$multiselectOptionHighlightBgColor: $color2;
$multiselectOptionHighlightColor: $color1;
$multiselectOptionSelectedBgColor: $color7;
$multiselectOptionSelectedColor: $color3;
$multiselectOptionHighlightSelectedBgColor: $color8;
$multiselectOptionHighlightSelectedColor: $color1;
$multiselectDisabledBgColor: darken($color1, 7%);
$multiselectDisabledColor: darken($color1, 35%);
$multiselectDisabledOptionBgColor: darken($color2, 3%);

$multiselectTagIcon: "\00D7";
$multiselectTagsBorderRadius: 0.3125rem;

.multiselect__spinner {
  position: absolute;
  right: 1px;
  top: 1px;
  width: 3rem;
  height: 2.1875rem;
  background: $spinnerBg;
  display: block;

  &:before,
  &:after {
    position: absolute;
    content: '';
    top: 50%;
    left: 50%;
    margin: 0.875rem 0 0 0.875rem;
    width: 1rem;
    height: 1rem;
    border-radius: 100%;
    border-color: $spinnerBorderColor transparent transparent;
    border-style: solid;
    border-width: 2px;
    box-shadow: 0 0 0 1px transparent;
  }
  &:before {
    animation: spinning 2.4s cubic-bezier(0.41, 0.26, 0.2, 0.62);
    animation-iteration-count: infinite;
  }
  &:after {
    animation: spinning 2.4s cubic-bezier(0.51, 0.09, 0.21, 0.8);
    animation-iteration-count: infinite;
  }
}
.multiselect__loading-transition {
  transition: opacity 0.4s ease-in-out;
  opacity: 1;
}
.multiselect__loading-enter,
.multiselect__loading-leave {
  opacity: 0;
}
.multiselect,
.multiselect__input,
.multiselect__single {
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: lighter;
}
.multiselect {
  box-sizing: content-box;

  * {
    box-sizing: border-box;
  }

  display: block;
  position: relative;
  width: 100%;
  min-height: 2.5rem;
  text-align: left;
  color: $multiselectColor;

  &:focus {
    outline: none;
  }

  &--active {
    z-index: 50;

    .multiselect__current,
    .multiselect__input,
    .multiselect__tags {
      border-bottom-left-radius: 0;
      border-bottom-right-radius: 0;
    }
    .multiselect__select {
      transform: rotateZ(180deg);
    }
  }
}
.multiselect__input,
.multiselect__single {
  position: relative;
  display: inline-block;
  min-height: 1.25rem;
  line-height: 1.25rem;
  border: none;
  border-radius: $multiselectTagsBorderRadius;
  background: $multiselectBg;
  padding: 1px 0 0 0.3125rem;
  width: auto;
  transition: border .1s ease;
  box-sizing: border-box;
  margin-bottom: 0.5rem;

  &:hover {
    border-color: $multiselectBorderColorHover;
  }

  &:focus {
    border-color: $multiselectBorderColorFocus;
    outline: none;
  }
}
.multiselect__single {
  padding-left: 0.375rem;
  margin-bottom: 0.5rem;
}
.multiselect__tags {
  min-height: 2.5rem;
  display: block;
  padding: 0.5rem 2.5rem 0 0.5rem;
  border-radius: $multiselectTagsBorderRadius;
  border: $multiselectTagsBorder;
  background: $multiselectTagsBgColor;
}
.multiselect__tag {
  position: relative;
  display: inline-block;
  padding: 0.25rem 1.625rem 0.25rem 0.625rem;
  border-radius: $multiselectTagsBorderRadius;
  margin-right: 0.625rem;
  color: $multiselectTagColor;
  line-height: 1;
  background: $multiselectTagBgColor;
  margin-bottom: 0.5rem;
}
.multiselect__tag-icon {
  cursor: pointer;
  margin-left: 7px;
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  font-weight: 700;
  font-style: initial;
  width: 1.375rem;
  text-align: center;
  line-height: 1.375rem;
  transition: all 0.2s ease;
  border-radius: $multiselectTagsBorderRadius;

  &:after {
    content: $multiselectTagIcon;
    color: $multiselectTagIconColor;
    font-size: 0.875rem;
  }
  &:focus, &:hover {
    background: $multiselectTagIconColorHover;

    &:after {
      color: $multiselectTagIconColorBgHover;
    }
  }
}
.multiselect__current {
  line-height: 1rem;
  min-height: 2.5rem;
  box-sizing: border-box;
  display: block;
  overflow: hidden;
  padding: 0.5rem 0.75rem 0;
  padding-right: 1.875rem;
  white-space: nowrap;
  margin: 0;
  text-decoration: none;
  border-radius: $multiselectTagsBorderRadius;
  border: 1px solid $multiselectCurrentBorderColor;
  cursor: pointer;
}
.multiselect__select {
  line-height: 1rem;
  display: block;
  position: absolute;
  box-sizing: border-box;
  width: 2.5rem;
  height: 2.375rem;
  right: 1px;
  top: 1px;
  padding: 0.25rem 0.5rem;
  margin: 0;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: transform 0.2s ease;

  &:before {
    position: relative;
    right: 0;
    top: 65%;
    color: $multiselectColor;
    margin-top: 0.25rem;
    border-style: solid;
    border-width: 0.3125rem 0.3125rem 0 0.3125rem;
    border-color: $multiselectBorderColor transparent transparent transparent;
    content: "";
  }
}
.multiselect__placeholder {
  color: $multiselectPlaceholderColor;
  display: inline-block;
  margin-bottom: 0.625rem;
  padding-top: 0.125rem;

  .multiselect--active & {
    display: none;
  }
}
.multiselect__content {
  position: absolute;
  list-style: none;
  display: block;
  background: $multiselectContentBgColor;
  width: 100%;
  max-height: 15rem;
  overflow: auto;
  padding: 0;
  margin: 0;
  border: 1px solid $multiselectContentBorderColor;
  border-top: none;
  border-bottom-left-radius: $multiselectTagsBorderRadius;
  border-bottom-right-radius: $multiselectTagsBorderRadius;
  z-index: 50;

  &::webkit-scrollbar {
    display: none;
  }
}
.multiselect__option {
  display: block;
  padding: 0.75rem;
  min-height: 2.5rem;
  line-height: 1rem;
  font-weight: 300;
  text-decoration: none;
  text-transform: none;
  vertical-align: middle;
  position: relative;
  cursor: pointer;

  &:after {
    top: 0;
    right: 0;
    position: absolute;
    line-height: 2.5rem;
    padding-right: 0.75rem;
    padding-left: 1.25rem;
  }
  &--highlight {
    background: $multiselectOptionHighlightBgColor;
    outline: none;
    color: $multiselectOptionHighlightColor;

    &:after {
      content: attr(data-select);
      color: $multiselectOptionHighlightColor;
    }
  }
  &--selected {
    background: $multiselectOptionSelectedBgColor;
    color: $multiselectOptionSelectedColor;
    font-weight: bold;

    &:after {
      content: attr(data-selected);
      font-weight: 300;
      color: darken($multiselectOptionSelectedBgColor, 20%);
    }
  }
}
.multiselect__option--selected.multiselect__option--highlight {
  background: $multiselectOptionHighlightSelectedBgColor;
  color: $multiselectOptionHighlightSelectedColor;
  font-weight: lighter;

  &:after {
    content: attr(data-deselect);
    color: $multiselectOptionHighlightSelectedColor;
  }
}
.multiselect--disabled {
  background: $multiselectDisabledBgColor;
  pointer-events: none;

  .multiselect__current,
  .multiselect__select {
    background: $multiselectDisabledBgColor;
    color: $multiselectDisabledColor;
  }
}
.multiselect__option--disabled {
  background: $multiselectDisabledBgColor;
  color: $multiselectDisabledColor;
  cursor: text;
  pointer-events: none;

  &:visited {
    color: $multiselectDisabledColor;
  }

  &:hover,
  &:focus {
    background: $multiselectDisabledOptionBgColor;
  }
}
.multiselect-transition {
  transition: all .3s ease;
}
.multiselect-enter, .multiselect-leave {
  opacity: 0;
  max-height: 0 !important;
}
shentao commented 6 years ago

@jeremykenedy I might reconsider my statement. It used to be built with sass back in the days. Given that the current CSS is extracted anyway it might be possible to create a simplified workflow with sass variables.

eFrane commented 5 years ago

Just a heads up: I've started diving into implementing this and will either report back here or open a PR for discussion in the next few days.

@shentao: I looked through issues and repo but didn't find any other prior work than what was commented here… am I missing something?

shentao commented 5 years ago

It was a while since I removed Sass. However, take into consideration that the Sass variables and Sass itself are a compilation step functionality. It’s not something you can apply on an already compiled library. Making it work would require the user to compile the library with the new Sass variables.

An alternative way to do it would be to use CSS variables with defaults. This would make it possible to customize the component even when using the recompiled bundle. However, this won’t work in Internet Explorer (the customization, the component would still use the default properties).

eFrane commented 5 years ago

I was aiming for having the style with variables in the component but offer two extracted stylesheets, one as css file which should work as it does now and one as sass/scss (should be decided, I'd favor the latter) which can then be integrated and customized.

shentao commented 5 years ago

That sounds good! Would you like to create a PR with that change?

eFrane commented 5 years ago

I will once I'm done, sure.

wujekbogdan commented 5 years ago

@eFrane @shentao It would be great if not only colours but also the size was configurable via scss. At the moment it's a bit tricky to change the size of the component, there's a lot of styles to overwrite.

eFrane commented 5 years ago

Okay so I just had an epiphany. If we can agree on permanently extracting the scss into a separate file, this whole issue could be solved by having the style block be something like

<style lang="scss" scoped>
@import "./path/to/vue-multiselect"; // EDIT: of course, scss local includes don't use url()...
</style>

vue-multiselect.scss then could even be splitted into a _variables and _classes file but htat might be overkill. Anyway, all of these scss-Files could then be simply added to the npm package to provide them to users.

Drawback of this solution would of course be losing the single file fanciness for the style section.

wujekbogdan commented 5 years ago

@shentao What are your plans for v3? Do you want to maintain the backwards compatibility? I'd like to implement a fully configurable version of Multiselect SCSS that would also include variables for size, spacings, etc, but I'm not sure what is the best approach. Can I modify the component's HTML structure (I wanted to write CSS that's fully BEM-compatible because the current styles not always follow the BEM rules)? If you want to keep the backwards compatibility then I won't do it.

shentao commented 5 years ago

@wujekbogdan that's a tough question. I want to keep it largely backward compatible, but the HTML structure will change. Take a look at the v3 branch. As you will see, the component is split into several smaller components. There is also a default component that is a composition combining the smaller components and the renderless core component.