Skip to content

Commit

Permalink
feat: add slider control, #30 (#117)
Browse files Browse the repository at this point in the history
Co-authored-by: Guillaume Chau <guillaume.b.chau@gmail.com>
  • Loading branch information
hugoattal and Akryum committed Jun 6, 2022
1 parent 719327a commit e7024e2
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 12 deletions.
4 changes: 0 additions & 4 deletions examples/vue3-percy/src/histoire.css
Expand Up @@ -6,7 +6,3 @@ html.htw-dark {
background: #27272a ;
color: #e9e9ed;
}

.__histoire-sandbox input {
border: solid 1px #ccc;
}
4 changes: 0 additions & 4 deletions examples/vue3-screenshot/src/histoire.css
Expand Up @@ -6,7 +6,3 @@ html.htw-dark {
background: #27272a ;
color: #e9e9ed;
}

.__histoire-sandbox input {
border: solid 1px #ccc;
}
6 changes: 6 additions & 0 deletions examples/vue3/src/components/Controls.story.vue
Expand Up @@ -40,6 +40,12 @@ function initState () {
v-model="state.number"
title="HstNumber"
/>
<HstSlider
v-model="state.number"
:min="0"
:max="100"
title="HstNumber"
/>
<HstTextarea
v-model="state.longText"
title="HstTextarea"
Expand Down
4 changes: 0 additions & 4 deletions examples/vue3/src/histoire.css
Expand Up @@ -6,7 +6,3 @@ html.htw-dark {
background: #27272a ;
color: #e9e9ed;
}

.__histoire-sandbox input {
border: solid 1px #ccc;
}
@@ -0,0 +1,35 @@
<script lang="ts" setup>
import { reactive } from 'vue'
import HstSlider from './HstSlider.vue'
const state = reactive({
value: 20,
min: 0,
max: 100,
step: 5,
})
</script>

<template>
<Story
title="HstSlider"
>
<HstSlider
v-model="state.value"
:step="state.step"
:min="state.min"
:max="state.max"
title="Slide"
/>
<pre>{{ state }}</pre>
<template #controls>
<HstSlider
v-model="state.value"
:step="state.step"
:min="state.min"
:max="state.max"
title="Value"
/>
</template>
</Story>
</template>
103 changes: 103 additions & 0 deletions packages/histoire-controls/src/components/slider/HstSlider.vue
@@ -0,0 +1,103 @@
<script lang="ts">
export default {
name: 'HstSlider',
inheritAttrs: false,
}
</script>

<script lang="ts" setup>
import { computed, ref } from 'vue'
import type { CSSProperties } from 'vue'
import HstWrapper from '../HstWrapper.vue'
import { VTooltip as vTooltip } from 'floating-vue'
const props = defineProps<{
title?: string
modelValue: number
min: number
max: number
}>()
const emit = defineEmits({
'update:modelValue': (newValue: number) => true,
})
const showTooltip = ref(false)
const input = ref<HTMLInputElement>(null)
const numberModel = computed({
get: () => props.modelValue,
set: value => {
emit('update:modelValue', value)
},
})
const percentage = computed(() => {
return (props.modelValue - props.min) / (props.max - props.min)
})
const tooltipStyle = computed<CSSProperties>(() => {
const gap = 8
if (input.value) {
const position = gap + ((input.value.clientWidth - 2 * gap) * percentage.value)
return {
left: position + 'px',
}
}
return {}
})
</script>

<template>
<HstWrapper
class="htw-items-center"
:title="title"
:class="$attrs.class"
:style="$attrs.style"
>
<div class="htw-relative htw-w-full htw-flex htw-items-center">
<div class="htw-absolute htw-inset-0 htw-flex htw-items-center">
<div class="htw-border htw-border-black/25 dark:htw-border-white/25 htw-h-1 htw-w-full htw-rounded-full" />
</div>
<input
ref="input"
v-model.number="numberModel"
class="htw-range-input htw-appearance-none htw-border-0 htw-bg-transparent htw-cursor-pointer htw-relative htw-w-full htw-m-0 htw-text-gray-700"
type="range"
v-bind="{ ...$attrs, class: null, style: null }"
@mouseover="showTooltip = true"
@mouseleave="showTooltip = false"
>
<div
v-if="showTooltip"
v-tooltip="{ content: modelValue.toString(), shown: true, distance: 16, delay: 0 }"
class="htw-absolute"
:style="tooltipStyle"
/>
</div>
</HstWrapper>
</template>

<style lang="pcss">
.htw-range-input {
&::-webkit-slider-thumb {
@apply htw-appearance-none htw-h-3 htw-w-3 htw-bg-white dark:htw-bg-gray-700 htw-border htw-border-solid htw-border-black/25 dark:htw-border-white/25 htw-rounded-full;
}
&:hover::-webkit-slider-thumb {
@apply !htw-bg-primary-500 !htw-border-primary-500;
}
}
/* Separate rules for -moz-range-thumb to prevent a bug with Safari that causes it to ignore custom style */
.htw-range-input {
&::-moz-range-thumb {
@apply htw-appearance-none htw-h-3 htw-w-3 htw-bg-white dark:htw-bg-gray-700 htw-border htw-border-solid htw-border-black/25 dark:htw-border-white/25 htw-rounded-full;
}
&:hover::-moz-range-thumb {
@apply !htw-bg-primary-500 !htw-border-primary-500;
}
}
</style>
3 changes: 3 additions & 0 deletions packages/histoire-controls/src/index.ts
Expand Up @@ -2,6 +2,7 @@ import type { App } from 'vue'
import HstCheckboxVue from './components/checkbox/HstCheckbox.vue'
import HstTextVue from './components/text/HstText.vue'
import HstNumberVue from './components/number/HstNumber.vue'
import HstSliderVue from './components/slider/HstSlider.vue'
import HstTextareaVue from './components/textarea/HstTextarea.vue'
import HstSelectVue from './components/select/HstSelect.vue'
import HstColorShadesVue from './components/design-tokens/HstColorShades.vue'
Expand All @@ -12,6 +13,7 @@ import HstCopyIconVue from './components/HstCopyIcon.vue'
export const HstCheckbox = HstCheckboxVue
export const HstText = HstTextVue
export const HstNumber = HstNumberVue
export const HstSlider = HstSliderVue
export const HstTextarea = HstTextareaVue
export const HstColorShades = HstColorShadesVue
export const HstTokenList = HstTokenListVue
Expand All @@ -22,6 +24,7 @@ export function registerVueComponents (app: App) {
app.component('HstCheckbox', HstCheckboxVue)
app.component('HstText', HstTextVue)
app.component('HstNumber', HstNumberVue)
app.component('HstSlider', HstSliderVue)
app.component('HstSelect', HstSelectVue)
app.component('HstTextarea', HstTextareaVue)
app.component('HstColorShades', HstColorShadesVue)
Expand Down

0 comments on commit e7024e2

Please sign in to comment.