diff --git a/package.json b/package.json index 2016ebb9..553d5154 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@soramitsu/soramitsu-js-ui", - "version": "1.0.41", + "version": "1.0.42", "private": false, "publishConfig": { "registry": "https://nexus.iroha.tech/repository/npm-soramitsu/" diff --git a/src/components/Checkbox/SCheckbox.vue b/src/components/Checkbox/SCheckbox.vue index eadd0203..a7b4564c 100644 --- a/src/components/Checkbox/SCheckbox.vue +++ b/src/components/Checkbox/SCheckbox.vue @@ -16,7 +16,7 @@ </template> <script lang="ts"> -import { Component, Mixins, ModelSync, Prop } from 'vue-property-decorator' +import { Component, Mixins, Prop } from 'vue-property-decorator' import ElCheckbox from 'element-ui/lib/checkbox' import SizeMixin from '../../mixins/SizeMixin' @@ -26,6 +26,10 @@ import BorderRadiusMixin from '../../mixins/BorderRadiusMixin' components: { ElCheckbox } }) export default class SCheckbox extends Mixins(SizeMixin, BorderRadiusMixin) { + /** + * Value of the checkbox item. Can be `string / number / boolean` + */ + @Prop() readonly value!: string | number | boolean /** * Label of the checkbox item */ @@ -58,11 +62,16 @@ export default class SCheckbox extends Mixins(SizeMixin, BorderRadiusMixin) { * `false` by default */ @Prop({ default: false, type: Boolean }) readonly indeterminate!: boolean - /** - * Value of the checkbox item. Can be `string / number / boolean` - */ - @ModelSync('value', 'input', { type: [String, Number, Boolean] }) - readonly model!: string | number | boolean + + get model (): string | number | boolean { + return this.value + } + + set model (value: string | number | boolean) { + if (this.value !== value) { + this.$emit('input', value) + } + } get computedClasses (): Array<string> { const cssClasses: Array<string> = [] diff --git a/src/components/DatePicker/SDatePicker/SDatePicker.vue b/src/components/DatePicker/SDatePicker/SDatePicker.vue index da25cbf4..1427dbaa 100644 --- a/src/components/DatePicker/SDatePicker/SDatePicker.vue +++ b/src/components/DatePicker/SDatePicker/SDatePicker.vue @@ -36,7 +36,7 @@ </template> <script lang="ts"> -import { Component, Mixins, ModelSync, Prop, Watch, Ref, Inject } from 'vue-property-decorator' +import { Component, Mixins, Prop, Watch, Ref, Inject } from 'vue-property-decorator' import ElDatePicker from 'element-ui/lib/date-picker' import { ElForm } from 'element-ui/types/form' import { ElFormItem } from 'element-ui/types/form-item' @@ -52,6 +52,11 @@ import { PickerTypes, PickerAlignment, InputTypes } from '../consts' components: { ElDatePicker, SIcon } }) export default class SDatePicker extends Mixins(SizeMixin, BorderRadiusMixin) { + /** + * Value of date picker component. Can be used with `v-model`. + * Can be date object / array with date objects for date range picker + */ + @Prop() readonly value!: any /** * Type of the date picker component. Available values: * @@ -172,12 +177,16 @@ export default class SDatePicker extends Mixins(SizeMixin, BorderRadiusMixin) { * `true` by default */ @Prop({ type: Boolean, default: true }) readonly validateEvent!: boolean - /** - * Value of date picker component. Can be used with `v-model`. - * Can be date object / array with date objects for date range picker - */ - @ModelSync('value', 'input') - readonly model!: any + + get model (): any { + return this.value + } + + set model (value: any) { + if (JSON.stringify(value) !== JSON.stringify(this.value)) { + this.$emit('input', value) + } + } @Watch('value') private handlePropChange (value: any): void { diff --git a/src/components/Radio/SRadio/SRadio.vue b/src/components/Radio/SRadio/SRadio.vue index 8afa1a3f..72c45bf8 100644 --- a/src/components/Radio/SRadio/SRadio.vue +++ b/src/components/Radio/SRadio/SRadio.vue @@ -7,13 +7,14 @@ :disabled="disabled" :border="border" :name="name" + @change="handleChange" > <slot></slot> </component> </template> <script lang="ts"> -import { Component, Mixins, Prop, ModelSync } from 'vue-property-decorator' +import { Component, Mixins, Prop } from 'vue-property-decorator' import ElRadio from 'element-ui/lib/radio' import ElRadioButton from 'element-ui/lib/radio-button' @@ -51,7 +52,17 @@ export default class SRadio extends Mixins(SizeMixin, DesignSystemInject) { /** * Binding value of the radio component. Can be `string` / `number` / `boolean` */ - @ModelSync('value', 'input', { type: [String, Number, Boolean] }) readonly model!: string | number | boolean + @Prop({ type: [String, Number, Boolean] }) readonly value!: string | number | boolean + + get model (): string | number | boolean { + return this.value + } + + set model (value: string | number | boolean) { + if (this.value !== value) { + this.$emit('input', value) + } + } get radioComponent () { return this.isRadioButton ? 'el-radio-button' : 'el-radio' @@ -67,5 +78,9 @@ export default class SRadio extends Mixins(SizeMixin, DesignSystemInject) { } return cssClasses } + + handleChange (value: string | number | boolean): void { + this.$emit('change', value) + } } </script> diff --git a/src/components/Radio/SRadioGroup/SRadioGroup.vue b/src/components/Radio/SRadioGroup/SRadioGroup.vue index 5dfab5cc..31dbc7c7 100644 --- a/src/components/Radio/SRadioGroup/SRadioGroup.vue +++ b/src/components/Radio/SRadioGroup/SRadioGroup.vue @@ -9,7 +9,7 @@ </template> <script lang="ts"> -import { Component, Mixins, Prop, ModelSync } from 'vue-property-decorator' +import { Component, Mixins, Prop } from 'vue-property-decorator' import ElRadioGroup from 'element-ui/lib/radio-group' import SizeMixin from '../../../mixins/SizeMixin' @@ -25,6 +25,16 @@ export default class SRadio extends Mixins(SizeMixin) { /** * Binding value of the radio group. Can be `string` / `number` / `boolean` */ - @ModelSync('value', 'input', { type: [String, Number, Boolean] }) readonly groupModel!: string | number | boolean + @Prop({ type: [String, Number, Boolean] }) readonly value!: string | number | boolean + + get groupModel (): string | number | boolean { + return this.value + } + + set groupModel (value: string | number | boolean) { + if (this.value !== value) { + this.$emit('input', value) + } + } } </script> diff --git a/src/components/Select/SSelect/SSelect.vue b/src/components/Select/SSelect/SSelect.vue index 80d067c2..4475905f 100644 --- a/src/components/Select/SSelect/SSelect.vue +++ b/src/components/Select/SSelect/SSelect.vue @@ -18,6 +18,7 @@ @focus="handleFocus" @visible-change="handleVisibleChange" @clear="handleClear" + @change="handleChange" :filterable="filterable" > <slot name="prefix" slot="prefix"></slot> @@ -28,7 +29,7 @@ </template> <script lang="ts"> -import { Component, Mixins, ModelSync, Prop, Watch, Ref, Inject } from 'vue-property-decorator' +import { Component, Mixins, Prop, Watch, Ref, Inject } from 'vue-property-decorator' import ElSelect from 'element-ui/lib/select' import { ElForm } from 'element-ui/types/form' import { ElFormItem } from 'element-ui/types/form-item' @@ -39,10 +40,18 @@ import DesignSystemInject from '../../DesignSystem/DesignSystemInject' import { Autocomplete } from '../../Input/consts' import { InputTypes } from '../consts' +type SingleSelectValue = boolean | string | number; +type MultipleSelectValue = Array<string | number>; +type SelectValue = SingleSelectValue | MultipleSelectValue; + @Component({ components: { ElSelect } }) export default class SSelect extends Mixins(SizeMixin, BorderRadiusMixin, DesignSystemInject) { + /** + * Selected value. Can be used with `v-model` + */ + @Prop({ type: [Boolean, String, Number, Array] }) readonly value!: SelectValue /** * Input type of the select component. Available values: `"input"`, `"select"`. * @@ -121,11 +130,16 @@ export default class SSelect extends Mixins(SizeMixin, BorderRadiusMixin, Design * `false` by default */ @Prop({ type: Boolean, default: false }) readonly filterable!: boolean - /** - * Selected value. Can be used with `v-model` - */ - @ModelSync('value', 'input') - readonly model!: any + + get model (): SelectValue { + return this.value + } + + set model (value: SelectValue) { + if (JSON.stringify(value) !== JSON.stringify(this.value)) { + this.$emit('input', value) + } + } @Ref('select') select!: any @@ -133,7 +147,7 @@ export default class SSelect extends Mixins(SizeMixin, BorderRadiusMixin, Design @Inject({ default: '', from: 'elFormItem' }) elFormItem!: ElFormItem @Watch('model') - private handleValueChange (value: any): void { + private handleValueChange (): void { this.updateInputValue() } @@ -148,7 +162,7 @@ export default class SSelect extends Mixins(SizeMixin, BorderRadiusMixin, Design tags.remove() } const input = this.select.$el.getElementsByClassName('el-input__inner')[0] as HTMLInputElement - input.value = this.model && this.model.length ? `${this.multipleTextPrefix || this.placeholder} (${this.model.length})` : '' + input.value = Array.isArray(this.model) && (this.model as MultipleSelectValue).length ? `${this.multipleTextPrefix || this.placeholder} (${this.model.length})` : '' } mounted (): void { @@ -193,7 +207,7 @@ export default class SSelect extends Mixins(SizeMixin, BorderRadiusMixin, Design if (this.disabled) { cssClasses.push('s-disabled') } - if ((!this.multiple && this.model) || (this.multiple && this.model.length !== 0)) { + if ((!this.multiple && this.model) || (this.multiple && Array.isArray(this.model) && this.model.length !== 0)) { cssClasses.push('s-has-value') } return cssClasses @@ -233,6 +247,10 @@ export default class SSelect extends Mixins(SizeMixin, BorderRadiusMixin, Design this.$emit('clear') } + handleChange (value: SelectValue): void { + this.$emit('change', value) + } + public focus (): void { this.select.focus() } diff --git a/src/components/Slider/SSlider.vue b/src/components/Slider/SSlider.vue index a0d7ea5f..0b957395 100644 --- a/src/components/Slider/SSlider.vue +++ b/src/components/Slider/SSlider.vue @@ -19,14 +19,13 @@ :range="range" :marks="marks" :disabled="disabled" - @input="handleInput" @change="handleChange" /> </div> </template> <script lang="ts"> -import { Vue, Component, ModelSync, Prop, Watch } from 'vue-property-decorator' +import { Vue, Component, Prop } from 'vue-property-decorator' import ElSlider from 'element-ui/lib/slider' import { SliderInputSize } from './consts' @@ -35,6 +34,10 @@ import { SliderInputSize } from './consts' components: { ElSlider } }) export default class SSlider extends Vue { + /** + * Binding value + */ + @Prop({ default: 0, type: [Number, Array] }) readonly value!: number | number[] /** * Minimum value */ @@ -99,14 +102,15 @@ export default class SSlider extends Vue { * Whether Slider is disabled */ @Prop({ default: false, type: Boolean }) readonly disabled!: boolean - /** - * Binding value - */ - @ModelSync('value', 'input', { default: 0, type: [Number, Array] }) - readonly model!: number | number[] - handleInput (value: number): void { - this.$emit('input', value) + get model (): number | number[] { + return this.value + } + + set model (value: number | number[]) { + if (JSON.stringify(value) !== JSON.stringify(this.value)) { + this.$emit('input', value) + } } handleChange (value: number): void { diff --git a/src/components/Switch/SSwitch.vue b/src/components/Switch/SSwitch.vue index eb2715be..a1a4842d 100644 --- a/src/components/Switch/SSwitch.vue +++ b/src/components/Switch/SSwitch.vue @@ -17,7 +17,7 @@ </template> <script lang="ts"> -import { Component, Mixins, ModelSync, Prop, Watch } from 'vue-property-decorator' +import { Component, Mixins, Prop } from 'vue-property-decorator' import ElSwitch from 'element-ui/lib/switch' import DesignSystemInject from '../DesignSystem/DesignSystemInject' @@ -65,8 +65,17 @@ export default class SSwitch extends Mixins(DesignSystemInject) { /** * Value of switch */ - @ModelSync('value', 'input', { type: [Boolean, String, Number] }) - readonly model!: boolean | string | number + @Prop({ type: [Boolean, String, Number] }) readonly value!: boolean | string | number + + get model (): boolean | string | number { + return this.value + } + + set model (value: boolean | string | number) { + if (this.value !== value) { + this.$emit('input', value) + } + } handleChange (value: boolean | string | number): void { this.$emit('change', value) diff --git a/src/components/Tab/STabs/STabs.vue b/src/components/Tab/STabs/STabs.vue index 1d954d3b..a5d0cde2 100644 --- a/src/components/Tab/STabs/STabs.vue +++ b/src/components/Tab/STabs/STabs.vue @@ -21,7 +21,7 @@ <script lang="ts"> import Vue from 'vue' -import { Component, Mixins, ModelSync, Prop } from 'vue-property-decorator' +import { Component, Mixins, Prop } from 'vue-property-decorator' import ElTabs from 'element-ui/lib/tabs' import DesignSystemInject from '../../DesignSystem/DesignSystemInject' @@ -32,6 +32,12 @@ import { TabsType, TabsPosition } from '../consts' components: { ElTabs } }) export default class STabs extends Mixins(BorderRadiusMixin, DesignSystemInject) { + /** + * Name of the selected tab. Can be used with `v-model`. + * + * First value by default + */ + @Prop({ type: String }) readonly value!: string /** * Type of tabs. Can be `"card"`/`"border-card"`/`"rounded"` or unset. * @@ -73,13 +79,16 @@ export default class STabs extends Mixins(BorderRadiusMixin, DesignSystemInject) * If `false` is returned or a `Promise` is returned and then is rejected, switching will be prevented */ @Prop({ type: Function }) readonly beforeLeave!: (activeName: string, oldActiveName: string) => (false | Promise<any>) - /** - * Name of the selected tab. Can be used with `v-model`. - * - * First value by default - */ - @ModelSync('value', 'input', { type: String }) - readonly model!: string + + get model (): string { + return this.value + } + + set model (value: string) { + if (this.value !== value) { + this.$emit('input', value) + } + } get computedType (): string { // neu tabs implemented only with TabsType.ROUNDED type diff --git a/src/components/Tooltip/STooltip.vue b/src/components/Tooltip/STooltip.vue index d25cf52c..8d6c1af9 100644 --- a/src/components/Tooltip/STooltip.vue +++ b/src/components/Tooltip/STooltip.vue @@ -22,7 +22,7 @@ </template> <script lang="ts"> -import { Component, Mixins, ModelSync, Prop, Watch, Ref } from 'vue-property-decorator' +import { Component, Mixins, Prop, Watch, Ref } from 'vue-property-decorator' import { PopoverPlacement } from 'element-ui/types/popover' import debounce from 'throttle-debounce/debounce' import ElTooltip from 'element-ui/lib/tooltip' @@ -115,8 +115,17 @@ export default class STooltip extends Mixins(BorderRadiusMixin, DesignSystemInje * * `false` by default */ - @ModelSync('value', 'input', { type: Boolean }) - readonly model!: boolean + @Prop({ type: Boolean }) readonly value!: boolean + + get model (): boolean { + return this.value + } + + set model (value: boolean) { + if (this.value !== value) { + this.$emit('input', value) + } + } @Ref('tooltip') tooltip!: any diff --git a/src/stories/Select/SSelect.stories.ts b/src/stories/Select/SSelect.stories.ts index 8a490058..f1b28ce3 100644 --- a/src/stories/Select/SSelect.stories.ts +++ b/src/stories/Select/SSelect.stories.ts @@ -117,39 +117,42 @@ const Template: Story = (args, { argTypes }) => ({ components: { SSelect, SOption, SRow, SCol }, props: Object.keys(argTypes), template: ` - <s-select - v-model="model" - :disabled="disabled" - :border-radius="borderRadius" - :loading="loading" - :size="size" - :multiple="multiple" - :input-type="inputType" - :clearable="clearable" - :multiple-limit="multipleLimit" - :placeholder="placeholder" - :multiple-text-prefix="multipleTextPrefix" - :loading-text="loadingText" - :no-data-text="noDataText" - :popper-class="borderRadius" - @change="handleChange" - :filterable="filterable" - > - <s-option - v-for="option in options" - :key="option.value" - :value="option.value" - :label="option.label" - /> - </s-select> + <s-row> + <s-select + v-model="model" + :disabled="disabled" + :border-radius="borderRadius" + :loading="loading" + :size="size" + :multiple="multiple" + :input-type="inputType" + :clearable="clearable" + :multiple-limit="multipleLimit" + :placeholder="placeholder" + :multiple-text-prefix="multipleTextPrefix" + :loading-text="loadingText" + :no-data-text="noDataText" + :popper-class="borderRadius" + @change="(value) => changeValue = value" + :filterable="filterable" + > + <s-option + v-for="option in options" + :key="option.value" + :value="option.value" + :label="option.label" + /> + </s-select> + <s-col :span="12" style="margin-top: 20px;"> + <span>v-model="{{ model }}", @change="{{ changeValue }}"</span> + </s-col> + </s-row> `, data: () => ({ model: '', + changeValue: '', options: optionsData - }), - methods: { - handleChange: (selected) => console.log('handleChange', selected) - } + }) }) export const Configurable = Template.bind({})