From 80788548b14c530623341f6c7bd174636e9cdbf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?= Date: Wed, 10 Apr 2024 10:39:58 +0200 Subject: [PATCH] I9857 slider (#343) * pkp/pkp-lib#9857 FieldSlider initial implementation * pkp/pkp-lib#9857 Update color classes * pkp/pkp-lib#9857 Add step prop --- .storybook/preview.js | 5 + package-lock.json | 9 + package.json | 1 + src/components/Form/FormFieldLabel.vue | 1 + src/components/Form/FormGroup.vue | 2 + src/components/Form/fields/FieldBase.vue | 11 +- src/components/Form/fields/FieldSlider.mdx | 7 + .../Form/fields/FieldSlider.stories.js | 34 ++++ src/components/Form/fields/FieldSlider.vue | 184 ++++++++++++++++++ src/components/Form/mocks/field-slider.js | 11 ++ src/composables/useFiltersForm.js | 8 + src/composables/useForm.js | 19 +- tailwind.config.js | 1 + 13 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 src/components/Form/fields/FieldSlider.mdx create mode 100644 src/components/Form/fields/FieldSlider.stories.js create mode 100644 src/components/Form/fields/FieldSlider.vue create mode 100644 src/components/Form/mocks/field-slider.js diff --git a/.storybook/preview.js b/.storybook/preview.js index 645534a6..659620cd 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -2,6 +2,7 @@ import {withThemeByDataAttribute} from '@storybook/addon-themes'; import {mockDateDecorator} from 'storybook-mock-date-decorator'; +import PrimeVue from 'primevue/config'; import {setup} from '@storybook/vue3'; import GlobalMixins from '@/mixins/global.js'; @@ -51,6 +52,10 @@ initialize({ setup((app) => { app.use(pinia); + app.use(PrimeVue, { + unstyled: true, + }); + app.mixin(GlobalMixins); app.use(FloatingVue, { diff --git a/package-lock.json b/package-lock.json index a0e97564..76bcb8b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "moment": "^2.29.4", "ofetch": "^1.3.3", "pinia": "^2.1.7", + "primevue": "^3.50.0", "tiny-emitter": "^2.1.0", "tinymce": "^5.10.7", "uuid": "^9.0.0", @@ -13056,6 +13057,14 @@ "node": ">= 0.8" } }, + "node_modules/primevue": { + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/primevue/-/primevue-3.50.0.tgz", + "integrity": "sha512-vYpQzvIXSmF0hWUkviHEGnwbFY/G8jI2RSxoa75noJloI2rWhzOX+JarJ8iaesVOr7b2se31N/p7zOx6uh3ddQ==", + "peerDependencies": { + "vue": "^3.0.0" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", diff --git a/package.json b/package.json index 48d404ae..3acec471 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "moment": "^2.29.4", "ofetch": "^1.3.3", "pinia": "^2.1.7", + "primevue": "^3.50.0", "tiny-emitter": "^2.1.0", "tinymce": "^5.10.7", "uuid": "^9.0.0", diff --git a/src/components/Form/FormFieldLabel.vue b/src/components/Form/FormFieldLabel.vue index 10e87702..8db34a08 100644 --- a/src/components/Form/FormFieldLabel.vue +++ b/src/components/Form/FormFieldLabel.vue @@ -18,6 +18,7 @@ export default { name: 'FormFieldLabel', props: { + labelId: String, controlId: String, label: String, localeLabel: String, diff --git a/src/components/Form/FormGroup.vue b/src/components/Form/FormGroup.vue index 5528f30e..abc2fced 100644 --- a/src/components/Form/FormGroup.vue +++ b/src/components/Form/FormGroup.vue @@ -75,6 +75,7 @@ import FieldShowEnsuringLink from './fields/FieldShowEnsuringLink.vue'; import FieldText from './fields/FieldText.vue'; import FieldTextarea from './fields/FieldTextarea.vue'; import FieldUpload from './fields/FieldUpload.vue'; +import FieldSlider from './fields/FieldSlider.vue'; import FieldUploadImage from './fields/FieldUploadImage.vue'; export default { @@ -101,6 +102,7 @@ export default { FieldShowEnsuringLink, FieldText, FieldTextarea, + FieldSlider, FieldUpload, FieldUploadImage, }, diff --git a/src/components/Form/fields/FieldBase.vue b/src/components/Form/fields/FieldBase.vue index 025cb3fe..2b76ad80 100644 --- a/src/components/Form/fields/FieldBase.vue +++ b/src/components/Form/fields/FieldBase.vue @@ -107,6 +107,15 @@ export default { return this.isMultilingual ? this.name + '-' + this.localeKey : this.name; }, + /** + * In case field is not using input element, its necessary to reference the label via aria-labelby (for example FieldSlider) + * + * @return {String} + */ + labelId() { + return this.compileId('control'); + }, + /** * A unique id for the label and control * @@ -185,7 +194,7 @@ export default { if (this.isMultilingual) { ids.push(this.multilingualProgressId); } - return ids.length ? ids.join(' ') : false; + return ids.length ? ids.join(' ') : undefined; }, /** diff --git a/src/components/Form/fields/FieldSlider.mdx b/src/components/Form/fields/FieldSlider.mdx new file mode 100644 index 00000000..867110f4 --- /dev/null +++ b/src/components/Form/fields/FieldSlider.mdx @@ -0,0 +1,7 @@ +import {Primary, Controls, Stories, Meta, ArgTypes} from '@storybook/blocks'; + +import * as FieldSliderStories from './FieldSlider.stories.js'; + + + +# FieldSlider diff --git a/src/components/Form/fields/FieldSlider.stories.js b/src/components/Form/fields/FieldSlider.stories.js new file mode 100644 index 00000000..0b2a324c --- /dev/null +++ b/src/components/Form/fields/FieldSlider.stories.js @@ -0,0 +1,34 @@ +import FieldSlider from './FieldSlider.vue'; + +import FieldBaseMock from '../mocks/field-base'; +import FieldSliderMock from '../mocks/field-slider'; + +export default { + title: 'Forms/FieldSlider', + component: FieldSlider, + render: (args) => ({ + components: {FieldSlider}, + setup() { + function change(name, prop, newValue, localeKey) { + if (localeKey) { + args[prop][localeKey] = newValue; + } else { + args[prop] = newValue; + } + } + + return {args, change}; + }, + template: ` + + `, + }), +}; + +export const Base = { + args: { + ...FieldBaseMock, + ...FieldSliderMock, + // description: 'slider description', + }, +}; diff --git a/src/components/Form/fields/FieldSlider.vue b/src/components/Form/fields/FieldSlider.vue new file mode 100644 index 00000000..395bbb8e --- /dev/null +++ b/src/components/Form/fields/FieldSlider.vue @@ -0,0 +1,184 @@ + + + diff --git a/src/components/Form/mocks/field-slider.js b/src/components/Form/mocks/field-slider.js new file mode 100644 index 00000000..da899673 --- /dev/null +++ b/src/components/Form/mocks/field-slider.js @@ -0,0 +1,11 @@ +export default { + name: 'slider', + component: 'field-slider', + label: 'Review Request Response - Before Due Date', + value: 20, + min: 0, + minLabel: 'None', + max: 35, + valueLabel: '{$value} days after due date', + valueLabelMin: 'No reminder set', +}; diff --git a/src/composables/useFiltersForm.js b/src/composables/useFiltersForm.js index a96fb22f..82ba31dd 100644 --- a/src/composables/useFiltersForm.js +++ b/src/composables/useFiltersForm.js @@ -56,6 +56,14 @@ export function useFiltersForm(_filtersForm) { label: option.label, value: option.value, }); + } else if (field.component === 'field-slider') { + if (fieldValue !== field.min) { + list.push({ + fieldLabel: field.label, + value: fieldValue, + label: fieldValue, + }); + } } else { list.push({ fieldLabel: field.label, diff --git a/src/composables/useForm.js b/src/composables/useForm.js index ac299936..0c91a01c 100644 --- a/src/composables/useForm.js +++ b/src/composables/useForm.js @@ -6,6 +6,20 @@ function getField(form, name) { return fields.find((field) => field.name === name); } +function getClearValue(field, localeKey = null) { + if (localeKey) { + if (field.component === 'field-slider') { + return field.min; + } + return Array.isArray(field.value[localeKey]) || field.selected ? [] : ''; + } + + if (field.component === 'field-slider') { + return field.min; + } + return Array.isArray(field.value) || field.selected ? [] : ''; +} + function mapFromSelectedToValue(selected) { return selected.map((iv) => iv.value); } @@ -43,13 +57,12 @@ export function useForm(_form) { const newValueMultilingual = {}; form.value.supportedFormLocales.forEach((localeObject) => { const localeKey = localeObject.key; - const newValue = - Array.isArray(field.value[localeKey]) || field.selected ? [] : ''; + const newValue = getClearValue(field, localeKey); newValueMultilingual[localeKey] = newValue; }); setValue(field.name, newValueMultilingual); } else { - const newValue = Array.isArray(field.value) || field.selected ? [] : ''; + const newValue = getClearValue(field); setValue(field.name, newValue); } }); diff --git a/tailwind.config.js b/tailwind.config.js index f9b74373..5d954bca 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -56,6 +56,7 @@ export default { }, borderRadius: { DEFAULT: '4px', + full: '9999px', }, boxShadow: { DEFAULT: '0 0 4px rgba(0, 0, 0, 0.5);',