From 8f4f78e6e0241fe7f9acd27ad638804c7243c657 Mon Sep 17 00:00:00 2001 From: Arnau Giralt Date: Tue, 11 Feb 2025 20:00:59 +0100 Subject: [PATCH 1/3] LITE-31805: Update card widget styles to match the specification --- components/src/stories/Card.stories.js | 29 ++++++++++++++--- components/src/widgets/card/widget.vue | 44 ++++++++++++++++---------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/components/src/stories/Card.stories.js b/components/src/stories/Card.stories.js index 73922a93..db8deeea 100644 --- a/components/src/stories/Card.stories.js +++ b/components/src/stories/Card.stories.js @@ -22,12 +22,9 @@ export const Component = { }, template: ` -
+
{{ args.content }}
-
- -
`, }), @@ -37,3 +34,27 @@ export const Component = { content: 'Card Content', }, }; + +export const ComponentWithAllSlots = { + render: (args) => ({ + setup() { + return { args }; + }, + template: ` + +
+ {{ args.content }} +
+ Custom title, link +

My custom subtitle :)

+
+ +
+
`, + }), + + args: { + title: 'Card title', + content: 'Card Content', + }, +}; diff --git a/components/src/widgets/card/widget.vue b/components/src/widgets/card/widget.vue index c73e0890..eb94372a 100644 --- a/components/src/widgets/card/widget.vue +++ b/components/src/widgets/card/widget.vue @@ -2,18 +2,16 @@
-

- {{ title }} -

-

- {{ subtitle }} -

+
+ +

{{ title }}

+
+
+
+ +

{{ subtitle }}

+
+
@@ -53,26 +51,38 @@ export default { text-decoration: inherit; color: inherit; - &__header{ + &__header { display: flex; - margin-bottom: 26px; + margin-bottom: 24px; align-items: start; flex-grow: 1; justify-content: space-between; } &__title { - line-height: 25px; - font-size: 20px; + line-height: 24px; + font-size: 18px; + font-weight: 500; margin: 0; + + p, + & ::slotted(p) { + margin: 0; + } } &__subtitle { + margin-top: 8px; font-size: 14px; + font-weight: 400; line-height: 20px; color: #707070; - margin: 0; white-space: pre-wrap; + + p, + & ::slotted(p) { + margin: 0; + } } &__title-container { From 19359dace7ad6b59532e206aec84f95e5671363a Mon Sep 17 00:00:00 2001 From: Arnau Giralt Date: Tue, 11 Feb 2025 20:01:21 +0100 Subject: [PATCH 2/3] LITE-31805: Add "disabled" state to Menu, Select, Textarea and Textfield widgets --- components/src/widgets/menu/widget.spec.js | 9 +++++++++ components/src/widgets/menu/widget.vue | 6 ++++++ components/src/widgets/select/widget.spec.js | 10 ++++++++++ components/src/widgets/select/widget.vue | 12 ++++++++++++ components/src/widgets/textarea/widget.vue | 18 +++++++++++++++++- .../src/widgets/textfield/widget.spec.js | 8 ++++++++ components/src/widgets/textfield/widget.vue | 10 +++++++++- 7 files changed, 71 insertions(+), 2 deletions(-) diff --git a/components/src/widgets/menu/widget.spec.js b/components/src/widgets/menu/widget.spec.js index 6e2dc90c..a7efa8d2 100644 --- a/components/src/widgets/menu/widget.spec.js +++ b/components/src/widgets/menu/widget.spec.js @@ -19,6 +19,15 @@ describe('Menu component', () => { expect(wrapper.vm.showMenu).toBe(false); }); + + it('does not toggle menu if disabled is true', async () => { + const wrapper = mount(Menu); + wrapper.vm.showMenu = true; + await wrapper.setProps({ disabled: true }); + wrapper.vm.toggle(wrapper.vm.showMenu); + + expect(wrapper.vm.showMenu).toBe(true); + }); }); describe('#handleClickOutside', () => { diff --git a/components/src/widgets/menu/widget.vue b/components/src/widgets/menu/widget.vue index 69063d7a..9aea3aae 100644 --- a/components/src/widgets/menu/widget.vue +++ b/components/src/widgets/menu/widget.vue @@ -42,6 +42,10 @@ const props = defineProps({ type: Boolean, default: false, }, + disabled: { + type: Boolean, + default: false, + }, }); const emit = defineEmits(['opened', 'closed']); @@ -56,6 +60,8 @@ const alignmentClass = computed(() => const fullWidthClass = computed(() => (props.fullWidth ? 'menu-content_full-width' : '')); const toggle = () => { + if (props.disabled) return; + showMenu.value = !showMenu.value; emit(showMenu.value ? 'opened' : 'closed'); }; diff --git a/components/src/widgets/select/widget.spec.js b/components/src/widgets/select/widget.spec.js index 3d29205b..0d39ff2f 100644 --- a/components/src/widgets/select/widget.spec.js +++ b/components/src/widgets/select/widget.spec.js @@ -40,6 +40,16 @@ describe('Select', () => { expect(wrapper.get('.select-input__label').text()).toEqual('My select'); }); + it('adds the disabled class if disabled is true', async () => { + await wrapper.setProps({ + disabled: true, + }); + + expect(wrapper.get('.select-input__selected').classes()).toContain( + 'select-input__selected_disabled', + ); + }); + it('renders a complex array of objects', async () => { await wrapper.setProps({ options: [ diff --git a/components/src/widgets/select/widget.vue b/components/src/widgets/select/widget.vue index 0f7ac779..d27f6cb3 100644 --- a/components/src/widgets/select/widget.vue +++ b/components/src/widgets/select/widget.vue @@ -14,12 +14,14 @@
{{ getDisplayText(selectedOption) }} @@ -134,6 +136,10 @@ const props = defineProps({ type: String, default: 'Nothing was found', }, + disabled: { + type: Boolean, + default: false, + }, }); const emit = defineEmits(['valueChange']); @@ -206,6 +212,12 @@ watch( border-color: #FF6A6A; outline: 1px solid #FF6A6A; } + + &_disabled { + border-style: dashed; + cursor: default; + color: #BDBDBD; + } } &__menu { diff --git a/components/src/widgets/textarea/widget.vue b/components/src/widgets/textarea/widget.vue index edcbc525..b36212fb 100644 --- a/components/src/widgets/textarea/widget.vue +++ b/components/src/widgets/textarea/widget.vue @@ -19,13 +19,14 @@ v-model="localValue" class="textarea-field__input" :class="inputClasses" + :disabled="disabled" :placeholder="placeholder" :readonly="props.readonly" :rows="rows" name="textarea" @focus="setFocus" @input.stop - > + />
[], }, + disabled: { + type: Boolean, + default: false, + }, }); const localValue = ref(''); @@ -117,6 +122,8 @@ const removeFocus = () => { }; const setFocus = () => { + if (props.disabled) return; + txtarea.value.focus(); isFocused.value = true; }; @@ -125,12 +132,14 @@ const computedClasses = computed(() => ({ 'textarea-field_focused': isFocused.value, 'textarea-field_invalid': !isValid.value, 'textarea-field_optional': !props.required, + 'textarea-field_disabled': props.disabled, })); const inputClasses = computed(() => ({ 'textarea-field__input_no-resize': props.autoGrow, 'textarea-field__input_no-border': props.noBorder, 'textarea-field__input_monospace': props.monospace, + 'textarea-field__input_disabled': props.disabled, })); onMounted(() => { @@ -188,6 +197,13 @@ watch(localValue, async (newValue) => { &_monospace { font-family: monospace; } + + &[disabled], + :disabled, + &_disabled { + border-style: dashed; + cursor: default; + } } &__label { diff --git a/components/src/widgets/textfield/widget.spec.js b/components/src/widgets/textfield/widget.spec.js index 8fb431d2..5df8cedf 100644 --- a/components/src/widgets/textfield/widget.spec.js +++ b/components/src/widgets/textfield/widget.spec.js @@ -60,6 +60,14 @@ describe('Textfield widget', () => { expect(wrapper.get('.text-field label').text()).toEqual('My input'); }); + + it('adds the disabled class if disabled is true', () => { + wrapper = mount(Textfield, { + props: { disabled: true }, + }); + + expect(wrapper.get('.text-field').classes()).toContain('text-field_disabled'); + }); }); describe('validation', () => { diff --git a/components/src/widgets/textfield/widget.vue b/components/src/widgets/textfield/widget.vue index 9105cc66..58dd14fa 100644 --- a/components/src/widgets/textfield/widget.vue +++ b/components/src/widgets/textfield/widget.vue @@ -21,10 +21,11 @@ v-model="localValue" class="text-field__input" :class="{ 'text-field__input_right': suffix }" + :autocomplete="browserAutocomplete ? 'on' : 'off'" + :disabled="disabled" :placeholder="placeholder" name="textfield" type="text" - :autocomplete="browserAutocomplete ? 'on' : 'off'" @focus="setFocus" @input.stop /> @@ -92,6 +93,10 @@ const props = defineProps({ type: Boolean, default: true, }, + disabled: { + type: Boolean, + default: false, + }, }); const emit = defineEmits(['input']); @@ -107,10 +112,13 @@ const computedClasses = computed(() => ({ 'text-field_focused': isFocused.value, 'text-field_invalid': !isValid.value, 'text-field_no-borders': props.noBorders, + 'text-field_disabled': props.disabled, })); const removeFocus = () => (isFocused.value = false); const setFocus = () => { + if (props.disabled) return; + isFocused.value = true; inputEl.value.focus(); }; From 23f0d3a3134f913cf2ac9a709e34b80e68a45fc7 Mon Sep 17 00:00:00 2001 From: Arnau Giralt Date: Tue, 11 Feb 2025 20:13:49 +0100 Subject: [PATCH 3/3] Create "precommit" package script, to run tests, lint, format and build sequentially --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ee010adc..ee2ab341 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "test:coverage": "vitest run --coverage.enabled", "test:watch": "vitest watch", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "precommit": "npm run test && npm run lint:fix && npm run format && npm run build" }, "dependencies": { "@cloudblueconnect/material-svg": "^1.0.43",