diff --git a/packages/docs/page-config/ui-elements/slider/examples/InvertedTrack.vue b/packages/docs/page-config/ui-elements/slider/examples/InvertedTrack.vue new file mode 100644 index 0000000000..ac6702cae7 --- /dev/null +++ b/packages/docs/page-config/ui-elements/slider/examples/InvertedTrack.vue @@ -0,0 +1,35 @@ + + + diff --git a/packages/docs/page-config/ui-elements/slider/index.ts b/packages/docs/page-config/ui-elements/slider/index.ts index 0dc87dc468..94251990c1 100644 --- a/packages/docs/page-config/ui-elements/slider/index.ts +++ b/packages/docs/page-config/ui-elements/slider/index.ts @@ -1,5 +1,5 @@ -import apiOptions from "./api-options"; import apiDescription from './api-description'; +import apiOptions from "./api-options"; export default definePageConfig({ blocks: [ @@ -62,6 +62,10 @@ export default definePageConfig({ title: "Vertical", description: "Vertical state of slider." }), + block.example("InvertedTrack", { + title: "Inverted", + description: "Inverted track fill." + }), block.subtitle('Accessibility'), block.paragraph('The component covers all the requirements of [w3 slider template](https://www.w3.org/WAI/ARIA/apg/patterns/slider/#wai-ariaroles,states,andproperties)[[target=_blank]]. It has [role=\"slider\"](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/slider_role)[[target=_blank]] and the following attributes: [aria-valuemin](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-valuemin)[[target=_blank]], [aria-valuemax](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-valuemax)[[target=_blank]], [aria-valuenow](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-valuenow)[[target=_blank]], [aria-label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label)[[target=_blank]], [aria-orientation](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-orientation)[[target=_blank]], [aria-disabled](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled)[[target=_blank]], [aria-readonly](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-readonly)[[target=_blank]].'), diff --git a/packages/ui/src/components/va-slider/VaSlider.stories.ts b/packages/ui/src/components/va-slider/VaSlider.stories.ts index 26a13de1fe..832c864b77 100644 --- a/packages/ui/src/components/va-slider/VaSlider.stories.ts +++ b/packages/ui/src/components/va-slider/VaSlider.stories.ts @@ -1,9 +1,9 @@ -import { getStoryId, getStoryIdAll, getStorySelector, getStorySelectorAll } from '../../../.storybook/interaction-utils/storySelector' -import { userEvent } from '../../../.storybook/interaction-utils/userEvent' +import { sleep } from '@/utils/sleep' +import { expect } from '@storybook/jest' import { fireEvent } from '@storybook/testing-library' import { StoryFn } from '@storybook/vue3' -import { expect } from '@storybook/jest' -import { sleep } from '@/utils/sleep' +import { getStoryId, getStoryIdAll, getStorySelector, getStorySelectorAll } from '../../../.storybook/interaction-utils/storySelector' +import { userEvent } from '../../../.storybook/interaction-utils/userEvent' import { VaSlider } from './' function getSlider () { @@ -678,3 +678,26 @@ Vertical.play = async ({ step }) => { expect(slider[2]).toHaveAttribute('aria-valuetext', '100') }) } + +export const invertTrack: StoryFn = () => ({ + components: { VaSlider }, + data: () => ({ value: 25 }), + template: ` + [default inverted] +
+ +
+ [vertical inverted] +
+ +
+ [default regular] +
+ +
+ [vertical regular] +
+ +
+ `, +}) diff --git a/packages/ui/src/components/va-slider/VaSlider.vue b/packages/ui/src/components/va-slider/VaSlider.vue index b5e9a212df..fd45a9fa02 100644 --- a/packages/ui/src/components/va-slider/VaSlider.vue +++ b/packages/ui/src/components/va-slider/VaSlider.vue @@ -229,6 +229,7 @@ const props = defineProps({ iconAppend: { type: String, default: '' }, vertical: { type: Boolean, default: false }, showTrack: { type: Boolean, default: true }, + invertTrack: { type: Boolean, default: false }, ariaLabel: useTranslationProp('$t:sliderValue'), ariaLabelDot: useTranslationProp('$t:sliderDot'), ariaLabelMaxDot: useTranslationProp('$t:sliderMaxDot'), @@ -267,6 +268,7 @@ const orders = computed(() => { const pinPositionStyle = computed(() => props.vertical ? 'bottom' : 'left') const trackSizeStyle = computed(() => props.vertical ? 'height' : 'width') +const trackPositionStyle = computed(() => props.vertical ? props.invertTrack ? 'top' : 'bottom' : props.invertTrack ? 'right' : 'left') const moreToLess = computed(() => Array.isArray(val.value) && (val.value[1] - stepComputed.value) < val.value[0]) @@ -307,9 +309,11 @@ const processedStyles = computed(() => { } as CSSProperties } else { const val0 = calculatePercentage(val.value) + const trackSizeStyleValue = props.invertTrack ? 100 - val0 : val0 return { - [trackSizeStyle.value]: `${val0 > 100 ? 100 : val0}%`, + [trackSizeStyle.value]: `${trackSizeStyleValue > 100 ? 100 : trackSizeStyleValue < 0 ? 0 : trackSizeStyleValue}%`, + [trackPositionStyle.value]: 0, backgroundColor: getColor(props.color), visibility: props.showTrack ? 'visible' : 'hidden', } as CSSProperties