diff --git a/package.json b/package.json index d2d00eac..d85285e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@soramitsu/soramitsu-js-ui", - "version": "0.4.1", + "version": "0.4.3", "private": false, "publishConfig": { "registry": "https://nexus.iroha.tech/repository/npm-soramitsu-private/" diff --git a/src/components/Radio/SRadio.vue b/src/components/Radio/SRadio.vue index a1bbe20d..d30b2246 100644 --- a/src/components/Radio/SRadio.vue +++ b/src/components/Radio/SRadio.vue @@ -1,5 +1,15 @@ + + diff --git a/src/components/Radio/index.ts b/src/components/Radio/index.ts index ec804fcd..9392d611 100644 --- a/src/components/Radio/index.ts +++ b/src/components/Radio/index.ts @@ -1,4 +1,5 @@ import SRadio from './SRadio.vue' +import SRadioGroup from './SRadioGroup.vue' import { RadioSize } from './consts' -export { SRadio, RadioSize } +export { SRadio, SRadioGroup, RadioSize } diff --git a/src/components/Slider/SSlider.vue b/src/components/Slider/SSlider.vue new file mode 100644 index 00000000..53a018bb --- /dev/null +++ b/src/components/Slider/SSlider.vue @@ -0,0 +1,132 @@ + + + diff --git a/src/components/Slider/consts.ts b/src/components/Slider/consts.ts new file mode 100644 index 00000000..3e4ca1e0 --- /dev/null +++ b/src/components/Slider/consts.ts @@ -0,0 +1,6 @@ +export enum SliderInputSize { + BIG = 'big', + MEDIUM = 'medium', + SMALL = 'small', + MINI = 'mini' +} diff --git a/src/components/Slider/index.ts b/src/components/Slider/index.ts new file mode 100644 index 00000000..67073618 --- /dev/null +++ b/src/components/Slider/index.ts @@ -0,0 +1,4 @@ +import SSlider from './SSlider.vue' +import { SliderInputSize } from './consts' + +export { SSlider, SliderInputSize } diff --git a/src/components/Switch/SSwitch.vue b/src/components/Switch/SSwitch.vue new file mode 100644 index 00000000..e8b85bc4 --- /dev/null +++ b/src/components/Switch/SSwitch.vue @@ -0,0 +1,82 @@ + + + diff --git a/src/components/Switch/index.ts b/src/components/Switch/index.ts new file mode 100644 index 00000000..2040039d --- /dev/null +++ b/src/components/Switch/index.ts @@ -0,0 +1,3 @@ +import SSwitch from './SSwitch.vue' + +export { SSwitch } diff --git a/src/components/index.ts b/src/components/index.ts index 573e5ba2..6e2a173a 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -23,7 +23,9 @@ import { SInput, SJsonInput } from './Input' import { SMain } from './Layout/Main' import { SMenu, SMenuItem, SMenuItemGroup, SSubmenu } from './Menu' import { SPagination } from './Pagination' -import { SRadio } from './Radio' +import { SSlider } from './Slider' +import { SSwitch } from './Switch' +import { SRadio, SRadioGroup } from './Radio' import { SRow } from './Layout/Row' import { SScrollSectionItem, SScrollSections } from './ScrollSections' import { SSelect, SOption, SOptionGroup } from './Select' @@ -64,11 +66,14 @@ export { SOptionGroup, SPagination, SRadio, + SRadioGroup, SRow, SScrollSectionItem, SScrollSections, SSelect, + SSlider, SSubmenu, + SSwitch, STab, STabs, STable, diff --git a/src/index.ts b/src/index.ts index ba537aae..68a17fe3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,11 +33,14 @@ import { SOptionGroup, SPagination, SRadio, + SRadioGroup, SRow, SScrollSectionItem, SScrollSections, SSelect, + SSlider, SSubmenu, + SSwitch, STab, STabs, STable, @@ -82,11 +85,14 @@ const components = [ { component: SOptionGroup, name: Components.SOptionGroup }, { component: SPagination, name: Components.SPagination }, { component: SRadio, name: Components.SRadio }, + { component: SRadioGroup, name: Components.SRadioGroup }, { component: SRow, name: Components.SRow }, { component: SScrollSectionItem, name: Components.SScrollSectionItem }, { component: SScrollSections, name: Components.SScrollSections }, { component: SSelect, name: Components.SSelect }, + { component: SSlider, name: Components.SSlider }, { component: SSubmenu, name: Components.SSubmenu }, + { component: SSwitch, name: Components.SSwitch }, { component: STab, name: Components.STab }, { component: STabs, name: Components.STabs }, { component: STable, name: Components.STable }, @@ -147,11 +153,14 @@ export { SOption, SOptionGroup, SRadio, + SRadioGroup, SRow, SScrollSectionItem, SScrollSections, SSelect, + SSlider, SSubmenu, + SSwitch, STab, STabs, STable, diff --git a/src/stories/SRadio.stories.ts b/src/stories/SRadio.stories.ts index 0b693797..15a21449 100644 --- a/src/stories/SRadio.stories.ts +++ b/src/stories/SRadio.stories.ts @@ -1,6 +1,6 @@ import { withKnobs, select, boolean } from '@storybook/addon-knobs' -import { SRadio, SRow, SCol } from '../components' +import { SRadio, SRadioGroup, SRow, SCol } from '../components' import { RadioSize } from '../components/Radio' export default { @@ -18,22 +18,22 @@ export const radioData = [ export const configurable = () => ({ components: { SRadio, SRow, SCol }, template: ` - - - {{ item.title }} - - - - v-model="{{ vModelValue }}", @change="{{ changeValue }}" - - `, + + + {{ item.title }} + + + + v-model="{{ vModelValue }}", @change="{{ changeValue }}" + + `, data: () => ({ vModelValue: 'first', changeValue: '', @@ -55,16 +55,16 @@ export const configurable = () => ({ export const disabled = () => ({ components: { SRadio, SRow }, template: ` - - {{ item.title }} - - `, + + {{ item.title }} + + `, data: () => ({ model: 'first', items: radioData @@ -74,18 +74,51 @@ export const disabled = () => ({ export const withBorders = () => ({ components: { SRadio, SRow }, template: ` - - {{ item.title }} - - `, + + {{ item.title }} + + `, data: () => ({ model: 'first', items: radioData }) }) + +export const radioButtonGroup = () => ({ + components: { SRadio, SRadioGroup, SRow }, + template: ` + + + {{ item.title }} + + +
+ v-model="{{ model }}" +
+
`, + data: () => ({ + model: 'first', + items: radioData + }), + props: { + size: { + default: select('Size', Object.values(RadioSize), RadioSize.MEDIUM) + }, + disabled: { + default: boolean('Disabled', false) + } + } +}) diff --git a/src/stories/SSlider.stories.ts b/src/stories/SSlider.stories.ts new file mode 100644 index 00000000..57dd9b62 --- /dev/null +++ b/src/stories/SSlider.stories.ts @@ -0,0 +1,178 @@ +import { text, number, boolean, select, object, withKnobs } from '@storybook/addon-knobs' + +import { SSlider, SliderInputSize } from '../components/Slider' + +export default { + component: SSlider, + title: 'Design System/Components/Slider', + decorators: [withKnobs], + excludeStories: /.*Data$/ +} + +export const configurable = () => ({ + components: { SSlider }, + template: `
+ + + v-model="{{ modelValue }}", @change="{{ changeValue }}" + +
`, + data: () => ({ + modelValue: 0, + changeValue: 0 + }), + props: { + min: { + default: number('Minimum value', 0) + }, + max: { + default: number('Maximum value', 100) + }, + showTooltip: { + default: boolean('Show Tooltip', true) + }, + step: { + default: number('Step size', 1) + }, + showStops: { + default: boolean('Show Stops', false) + }, + disabled: { + default: boolean('Disabled', false) + } + } +}) + +export const withCustomLabelAttribute = () => ({ + components: { SSlider }, + template: `
+ + + v-model="{{ modelValue }}", @change="{{ changeValue }}", label="{{ label }}" + +
`, + data: () => ({ + modelValue: 0, + changeValue: 0, + label: 'Custom slider label value' + }) +}) + +export const withInitValue = () => ({ + components: { SSlider }, + template: `
+ + + v-model="{{ modelValue }}", @change="{{ changeValue }}" + +
`, + data: () => ({ + modelValue: 50, + changeValue: 0 + }) +}) + +export const withInput = () => ({ + components: { SSlider }, + template: `
+ + + v-model="{{ modelValue }}", @change="{{ changeValue }}" + +
`, + data: () => ({ + modelValue: 0, + changeValue: 0 + }), + props: { + showInput: { + default: boolean('Show Input', true) + }, + showInputControls: { + default: boolean('Show Input Controls', true) + }, + inputSize: { + default: select('Size of the input box', Object.values(SliderInputSize), SliderInputSize.SMALL) + }, + debounce: { + default: number('Debounce delay when typing (in milliseconds)', 300) + } + } +}) + +export const withRange = () => ({ + components: { SSlider }, + template: `
+ + + v-model="{{ modelValue }}", @change="{{ changeValue }}" + +
`, + data: () => ({ + modelValue: [0, 0], + changeValue: [0, 0] + }), + props: { + range: { + default: boolean('Range', true) + }, + marks: { + default: object('Marks', { + 0: '0°C', + 8: '8°C', + 37: '37°C' + }) + } + } +}) + +export const verticalMode = () => ({ + components: { SSlider }, + template: `
+ + + v-model="{{ modelValue }}", @change="{{ changeValue }}" + +
`, + data: () => ({ + modelValue: 0, + changeValue: 0 + }), + props: { + height: { + default: text('Height', '200px') + } + } +}) diff --git a/src/stories/SSwitch.stories.ts b/src/stories/SSwitch.stories.ts new file mode 100644 index 00000000..62c76629 --- /dev/null +++ b/src/stories/SSwitch.stories.ts @@ -0,0 +1,53 @@ +import { text, number, boolean, withKnobs } from '@storybook/addon-knobs' + +import { SSwitch } from '../components/Switch' + +export default { + component: SSwitch, + title: 'Design System/Components/Switch', + decorators: [withKnobs], + excludeStories: /.*Data$/ +} + +export const configurable = () => ({ + components: { SSwitch }, + template: `
+ + + v-model="{{ modelValue }}", @change="{{ changeValue }}" + +
`, + data: () => ({ + modelValue: true, + changeValue: true + }), + props: { + activeText: { + default: text('Active Text', '') + }, + inactiveText: { + default: text('Inactive Text', '') + }, + activeValue: { + default: text('Active Value', 'Active Value') + }, + inactiveValue: { + default: text('Inactive Value', 'Inactive Value') + }, + width: { + default: number('Width', 40) + }, + disabled: { + default: boolean('Disabled', false) + } + } +}) diff --git a/src/styles/index.scss b/src/styles/index.scss index 9b2002d7..ae273633 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -18,6 +18,8 @@ @import "./radio"; @import "./scroll-sections"; @import "./select"; +@import "./slider"; +@import "./switch"; @import "./tabs"; @import "./table"; @import "./tooltip"; diff --git a/src/styles/radio.scss b/src/styles/radio.scss index f7a0079d..8b92601b 100644 --- a/src/styles/radio.scss +++ b/src/styles/radio.scss @@ -1,6 +1,29 @@ @import "./variables"; @import "./common"; +$radio-button-class: ".el-radio-button"; +$radio-button-border-width: 1px; +$radio-button-border-color: var(--s-color-main-brand); + +@mixin radio-button-size( + $modifier: "small", + $size: $s-size-small, + $font-size: $s-font-size-small +) { + $radio-button-vertical-padding: #{($size - $font-size) / 2 - $radio-button-border-width}; + #{$radio-button-class} { + &--#{$modifier} { + height: $size; + line-height: $size; + #{$radio-button-class}__inner { + padding-top: $radio-button-vertical-padding; + padding-bottom: $radio-button-vertical-padding; + font-size: $font-size; + } + } + } +} + .el-radio { color: var(--s-color-basic-black); &.s-big { @@ -98,4 +121,91 @@ } } } + &-button { + &:hover { + #{$radio-button-class}__inner { + border-color: $radio-button-border-color; + color: var(--s-color-main-brand); + } + &:not(:first-child):not(.is-disabled) { + #{$radio-button-class}__inner { + &:before { + opacity: 1; + } + } + } + } + &:not(:first-child):not(.is-disabled) { + #{$radio-button-class}__inner { + position: relative; + &:before { + content: ""; + position: absolute; + display: block; + opacity: 0; + background-color: $radio-button-border-color; + height: calc(100% + #{$radio-button-border-width * 2}); + width: $radio-button-border-width; + left: -#{$radio-button-border-width}; + top: -#{$radio-button-border-width}; + transition: inherit; + transition-property: opacity; + } + } + } + &.is-disabled { + #{$radio-button-class}__inner { + color: var(--s-color-neutral-inactive); + } + } + &.is-disabled, + &.is-disabled:hover { + #{$radio-button-class}__inner { + border-color: var(--s-color-neutral-border); + } + } + &.is-active { + &:hover { + #{$radio-button-class}__inner { + background-color: var(--s-color-main-hover); + border-color: var(--s-color-main-hover); + } + } + &.is-disabled { + #{$radio-button-class}__inner { + color: var(--s-color-basic-white); + } + } + &.is-disabled, + &.is-disabled:hover { + #{$radio-button-class}__inner { + background-color: var(--s-color-main-inactive); + border-color: var(--s-color-main-inactive); + } + } + } + } + &-group { + @include radio-button-size; + @include radio-button-size("medium", $s-size-medium, $s-font-size-big); + @include radio-button-size("big", $s-size-big, $s-font-size-big); + #{$radio-button-class} { + &__inner { + background-color: var(--s-color-basic-white); + border-color: var(--s-color-neutral-border); + color: var(--s-color-basic-black); + } + #{$radio-button-class}__inner { + box-shadow: none; + } + } + .is-disabled #{$radio-button-class}__inner { + background-color: var(--s-color-basic-white); + } + .is-active #{$radio-button-class}__inner { + background-color: var(--s-color-main-brand); + border-color: var(--s-color-main-brand); + color: var(--s-color-basic-white); + } + } } diff --git a/src/styles/slider.scss b/src/styles/slider.scss new file mode 100644 index 00000000..7940b83e --- /dev/null +++ b/src/styles/slider.scss @@ -0,0 +1,100 @@ +@import "./variables"; + +@mixin slider-colors( + $background-color: --s-color-main-brand, + $border-color: $background-color, + $color: false +) { + background-color: var($background-color); + border-color: var($border-color); + + @if $color != false { + color: var($color); + } +} + +@mixin slider-input-size($modifier: "mini", $size: $s-size-mini) { + .el-input-number--#{$modifier} { + line-height: $size; + .el-input__inner { + height: $size; + line-height: $size; + } + } +} + +.s-slider { + .el-slider__runway, + .disabled .el-slider__runway { + background-color: var(--s-color-neutral-placeholder); + } + .el-slider { + &__button { + @include slider-colors; + } + &__marks-text { + color: var(--s-color-basic-black); + } + &__bar { + background-color: var(--s-color-main-brand); + } + } + .disabled { + .el-slider__bar { + background-color: var(--s-color-neutral-border); + } + .el-slider__button { + @include slider-colors(--s-color-neutral-border); + } + } + .el-input { + &__inner { + @include slider-colors(--s-color-neutral-placeholder); + &:hover:not([disabled]):not(:focus) { + @include slider-colors(--s-color-neutral-hover); + } + &:focus { + @include slider-colors(--s-color-basic-white, --s-color-neutral-border); + } + } + &-number { + &__decrease, + &__increase { + height: 100%; + top: 0; + color: var(--s-color-basic-white); + @include slider-colors($color: --s-color-basic-white); + &:hover:not(.is-disabled) + ~ .el-input + .el-input__inner:not(.is-disabled) { + border-color: var(--s-color-neutral-hover); + } + &.is-disabled { + @include slider-colors( + $background-color: --s-color-main-inactive, + $color: --s-color-basic-white + ); + } + } + &__decrease { + left: 0; + } + &__increase { + right: 0; + } + &.is-disabled { + .el-input-number__decrease, + .el-input-number__increase { + @include slider-colors( + $background-color: --s-color-main-inactive, + $color: --s-color-basic-white + ); + } + } + } + } + @include slider-input-size; + @include slider-input-size("small", $s-size-small); + @include slider-input-size("medium", $s-size-medium); + @include slider-input-size("big", $s-size-big); +} diff --git a/src/styles/switch.scss b/src/styles/switch.scss new file mode 100644 index 00000000..ef8f32d1 --- /dev/null +++ b/src/styles/switch.scss @@ -0,0 +1,47 @@ +@import "./variables"; + +$switch-class: ".el-switch"; + +.s-switch { + #{$switch-class} { + &__label { + color: var(--s-color-basic-black); + &.is-active { + color: var(--s-color-main-brand); + } + } + &__core { + border-color: var(--s-color-neutral-border); + background-color: var(--s-color-neutral-border); + &:after { + background-color: var(--s-color-basic-white); + } + } + &:hover, + &.is-checked:hover { + #{$switch-class}__core { + background-color: var(--s-color-main-hover); + border-color: var(--s-color-main-hover); + } + } + &.is-disabled { + opacity: 1; + #{$switch-class}__core { + background-color: var(--s-color-neutral-placeholder); + border-color: var(--s-color-neutral-placeholder); + } + } + &.is-checked { + #{$switch-class}__core { + background-color: var(--s-color-main-brand); + border-color: var(--s-color-main-brand); + } + &.is-disabled { + #{$switch-class}__core { + background-color: var(--s-color-main-inactive); + border-color: var(--s-color-main-inactive); + } + } + } + } +} diff --git a/src/styles/variables.scss b/src/styles/variables.scss index 238ae45c..4d403700 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -21,11 +21,16 @@ $s-color-basic-white: #FFF !default; $s-size-big: 56px !default; $s-size-medium: 40px !default; $s-size-small: 32px !default; +$s-size-mini: 24px !default; $s-border-radius-default: 4px !default; // Fonts $font-family-default: 'Sora', sans-serif !important; $font-family-mono: 'JetBrainsMono', monospace !important; +// Font sizes +$s-font-size-big: 14px !default; +$s-font-size-small: 12px !default; + // Responsive $--sm: 640px !default; $--md: 1024px !default; diff --git a/src/types/components.ts b/src/types/components.ts index 3c4d1a20..2f3923f9 100644 --- a/src/types/components.ts +++ b/src/types/components.ts @@ -31,11 +31,14 @@ export enum Components { SOptionGroup = 'SOptionGroup', SPagination = 'SPagination', SRadio = 'SRadio', + SRadioGroup = 'SRadioGroup', SRow = 'SRow', SScrollSectionItem = 'SScrollSectionItem', SScrollSections = 'SScrollSections', SSelect = 'SSelect', + SSlider = 'SSlider', SSubmenu = 'SSubmenu', + SSwitch = 'SSwitch', STab = 'STab', STabs = 'STabs', STable = 'STable',