From 829d484897497106629a6913b97b06e0943b68d7 Mon Sep 17 00:00:00 2001 From: nerim Date: Mon, 29 Apr 2024 16:44:56 +0200 Subject: [PATCH] Add textarea, alert and radio button --- components/src/index.js | 3 + components/src/stories/Alert.stories.js | 30 ++++++ components/src/stories/Radio.stories.js | 32 ++++++ components/src/stories/Textarea.stories.js | 36 +++++++ components/src/widgets/alert/widget.spec.js | 46 +++++++++ components/src/widgets/alert/widget.vue | 97 +++++++++++++++++++ components/src/widgets/radio/widget.spec.js | 91 +++++++++++++++++ components/src/widgets/radio/widget.vue | 86 ++++++++++++++++ .../src/widgets/textarea/widget.spec.js | 52 ++++++++++ components/src/widgets/textarea/widget.vue | 96 ++++++++++++++++++ 10 files changed, 569 insertions(+) create mode 100644 components/src/stories/Alert.stories.js create mode 100644 components/src/stories/Radio.stories.js create mode 100644 components/src/stories/Textarea.stories.js create mode 100644 components/src/widgets/alert/widget.spec.js create mode 100644 components/src/widgets/alert/widget.vue create mode 100644 components/src/widgets/radio/widget.spec.js create mode 100644 components/src/widgets/radio/widget.vue create mode 100644 components/src/widgets/textarea/widget.spec.js create mode 100644 components/src/widgets/textarea/widget.vue diff --git a/components/src/index.js b/components/src/index.js index 08d3550e..baafac2a 100644 --- a/components/src/index.js +++ b/components/src/index.js @@ -15,6 +15,9 @@ export { default as Table } from '~widgets/table/widget.vue'; export { default as ComplexTable } from './widgets/complexTable/widget.vue'; export { default as Button } from '~widgets/button/widget.vue'; export { default as Menu } from '~widgets/menu/widget.vue'; +export { default as Textarea } from '~widgets/textarea/widget.vue'; +export { default as Alert } from '~widgets/alert/widget.vue'; +export { default as Radio } from '~widgets/radio/widget.vue'; export { default as store } from '~core/store'; export { default as bus } from '~core/eventBus'; diff --git a/components/src/stories/Alert.stories.js b/components/src/stories/Alert.stories.js new file mode 100644 index 00000000..6e6cc703 --- /dev/null +++ b/components/src/stories/Alert.stories.js @@ -0,0 +1,30 @@ +import Alert from '~widgets/alert/widget.vue'; +import registerWidget from '~core/registerWidget'; + +registerWidget('ui-alert', Alert); + +export const Component = { + render: (args) => ({ + setup() { + return { args }; + }, + template: ``, + }), + + args: { + message: 'This is an alert item', + }, +}; + +export default { + title: 'Components/Alert', + component: Alert, + parameters: { + layout: 'centered', + }, + argTypes: { + message: 'text', + icon: 'text', + tyoe: 'text', + }, +}; diff --git a/components/src/stories/Radio.stories.js b/components/src/stories/Radio.stories.js new file mode 100644 index 00000000..a595860a --- /dev/null +++ b/components/src/stories/Radio.stories.js @@ -0,0 +1,32 @@ +import Radio from '~widgets/radio/widget.vue'; +import registerWidget from '~core/registerWidget'; + +registerWidget('ui-radio', Radio); + +export const Component = { + render: (args) => ({ + setup() { + return { args }; + }, + template: ``, + }), + + args: { + label: 'Option', + selectedValue: 'foo', + radioValue: 'foo', + }, +}; + +export default { + title: 'Components/Radio', + component: Radio, + parameters: { + layout: 'centered', + }, + argTypes: { + label: 'text', + radioValue: 'text', + selectedValue: 'text', + }, +}; diff --git a/components/src/stories/Textarea.stories.js b/components/src/stories/Textarea.stories.js new file mode 100644 index 00000000..f8aa1bb0 --- /dev/null +++ b/components/src/stories/Textarea.stories.js @@ -0,0 +1,36 @@ +import Textarea from '~widgets/textarea/widget.vue'; +import registerWidget from '~core/registerWidget'; + +registerWidget('ui-textarea', Textarea); + +export const Basic = { + name: 'Basic options', + render: (args) => ({ + setup() { + return { args }; + }, + template: '', + }), + + args: { + value: '', + placeholder: 'Placeholder text', + }, +}; + +export default { + title: 'Components/Textarea', + component: Textarea, + parameters: { + layout: 'centered', + }, + argTypes: { + value: 'text', + readonly: 'boolean', + placeholder: 'text', + required: 'boolean', + autoGrow: 'boolean', + noBorder: 'boolean', + rows: 'number', + }, +}; diff --git a/components/src/widgets/alert/widget.spec.js b/components/src/widgets/alert/widget.spec.js new file mode 100644 index 00000000..21ac8ff2 --- /dev/null +++ b/components/src/widgets/alert/widget.spec.js @@ -0,0 +1,46 @@ +import { shallowMount } from '@vue/test-utils'; + +import Alert from './widget.vue'; + +describe('Alert component', () => { + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(Alert, { + props: { + modelValue: true, + message: 'this is a message', + type: 'success', + }, + global: { + renderStubDefaultSlot: true, + }, + }); + }); + + describe('render', () => { + test('renders the base component', () => { + expect(wrapper.get('.alert-holder').attributes()).toEqual( + expect.objectContaining({ + class: 'alert-holder alert_success', + modelvalue: 'true', + }), + ); + + const text = wrapper.find('.alert__text'); + + expect(text.text()).toEqual('this is a message'); + + const icon = wrapper.find('ui-icon'); + + expect(icon.exists()).toEqual(true); + expect(icon.attributes()).toEqual( + expect.objectContaining({ + iconname: 'googleInfoBaseline', + color: '#0bb071', + size: '24', + }), + ); + }); + }); +}); diff --git a/components/src/widgets/alert/widget.vue b/components/src/widgets/alert/widget.vue new file mode 100644 index 00000000..65a192a1 --- /dev/null +++ b/components/src/widgets/alert/widget.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/components/src/widgets/radio/widget.spec.js b/components/src/widgets/radio/widget.spec.js new file mode 100644 index 00000000..c1546465 --- /dev/null +++ b/components/src/widgets/radio/widget.spec.js @@ -0,0 +1,91 @@ +import RadioInput from './widget.vue'; +import { shallowMount } from '@vue/test-utils'; + +describe('RadioInput component', () => { + describe('render', () => { + describe('when is checked', () => { + test('renders the base component', () => { + const wrapper = shallowMount(RadioInput, { + props: { + radioValue: 'foo', + label: 'My radio input', + selectedValue: 'foo', + }, + }); + + expect(wrapper.get('.radio-input ui-icon').attributes()).toEqual( + expect.objectContaining({ + iconname: 'googleRadioButtonCheckedBaseline', + color: '#2C98F0', + }), + ); + expect(wrapper.get('.radio-input__label').classes()).not.toContain( + 'radio-input__label_empty', + ); + expect(wrapper.get('.radio-input__label-text').text()).toEqual('My radio input'); + expect(wrapper.vm.isSelected).toEqual(true); + expect(wrapper.vm.icon).toEqual('googleRadioButtonCheckedBaseline'); + expect(wrapper.vm.iconColor).toEqual('#2C98F0'); + }); + }); + + describe('when is unchecked', () => { + test('renders the base component', () => { + const wrapper = shallowMount(RadioInput, { + props: { + radioValue: 'foo', + label: 'My radio input', + selectedValue: 'bar', + }, + }); + + expect(wrapper.get('.radio-input ui-icon').attributes()).toEqual( + expect.objectContaining({ + iconname: 'googleRadioButtonUncheckedBaseline', + color: '', + }), + ); + expect(wrapper.get('.radio-input__label').classes()).not.toContain( + 'radio-input__label_empty', + ); + expect(wrapper.get('.radio-input__label-text').text()).toEqual('My radio input'); + expect(wrapper.vm.isSelected).toEqual(false); + expect(wrapper.vm.icon).toEqual('googleRadioButtonUncheckedBaseline'); + expect(wrapper.vm.iconColor).toEqual(''); + }); + }); + + describe('when there is no label', () => { + test('adds the "radio-input__label_empty" class to the label element if there is no label', () => { + const wrapper = shallowMount(RadioInput, { + props: { + radioValue: 'foo', + selectedValue: 'foo', + label: '', + }, + }); + + expect(wrapper.get('.radio-input__label').classes()).toContain('radio-input__label_empty'); + }); + }); + }); + + describe('events', () => { + describe('#select', () => { + test('it triggers the selected event with the radio value', () => { + const wrapper = shallowMount(RadioInput, { + props: { + radioValue: 'bar', + selectedValue: 'foo', + label: 'label', + }, + }); + + wrapper.vm.select(); + + expect(wrapper.emitted('selected')).toBeTruthy(); + expect(wrapper.emitted()).toEqual({ selected: [['bar']] }); + }); + }); + }); +}); diff --git a/components/src/widgets/radio/widget.vue b/components/src/widgets/radio/widget.vue new file mode 100644 index 00000000..a5b653bb --- /dev/null +++ b/components/src/widgets/radio/widget.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/components/src/widgets/textarea/widget.spec.js b/components/src/widgets/textarea/widget.spec.js new file mode 100644 index 00000000..fa90a992 --- /dev/null +++ b/components/src/widgets/textarea/widget.spec.js @@ -0,0 +1,52 @@ +import { shallowMount } from '@vue/test-utils'; + +import TextArea from './widget.vue'; + +describe('TextArea component', () => { + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(TextArea, { + props: { + modelValue: 'textarea text', + noBorder: true, + autoGrow: true, + rows: 4, + }, + global: { + renderStubDefaultSlot: true, + }, + }); + }); + + describe('render', () => { + test('renders the base component', () => { + expect(wrapper.get('textarea').attributes()).toEqual( + expect.objectContaining({ + class: 'textarea-input textarea-input__no-resize textarea-input__no-border', + rows: '4', + }), + ); + }); + }); + + describe('#calculateInputHeight', () => { + test('calculates and sets the right height when is autogrow', () => { + wrapper.vm.calculateInputHeight(); + + expect(wrapper.get('textarea').wrapperElement.style.height).toEqual('96px'); + }); + }); + + describe('#onMounted', () => { + test('calls calculateInputHeight and sets the right height', () => { + expect(wrapper.get('textarea').wrapperElement.style.height).toEqual('96px'); + }); + }); + + describe('watch', () => { + test('calls calculateInputHeight and sets the right height', () => { + expect(wrapper.get('textarea').wrapperElement.style.height).toEqual('96px'); + }); + }); +}); diff --git a/components/src/widgets/textarea/widget.vue b/components/src/widgets/textarea/widget.vue new file mode 100644 index 00000000..b90aec2e --- /dev/null +++ b/components/src/widgets/textarea/widget.vue @@ -0,0 +1,96 @@ + + + + +