@nexxtmove/ui 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Slider/Slider.vue.d.ts +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +524 -437
- package/dist/nuxt.js +1 -0
- package/package.json +1 -1
- package/src/components/Slider/Slider.vue +146 -0
- package/src/components.json +1 -0
- package/src/index.ts +1 -0
package/dist/nuxt.js
CHANGED
|
@@ -47599,6 +47599,7 @@ var Xw, Zw, Qw, $w, eT, tT = f((() => {
|
|
|
47599
47599
|
NexxtSidebarMenuItem: "components/SidebarMenuItem/SidebarMenuItem.vue",
|
|
47600
47600
|
NexxtSkeleton: "components/Skeleton/Skeleton.vue",
|
|
47601
47601
|
NexxtSkeletonPropertyCard: "components/SkeletonPropertyCard/SkeletonPropertyCard.vue",
|
|
47602
|
+
NexxtSlider: "components/Slider/Slider.vue",
|
|
47602
47603
|
NexxtSocialIcons: "components/SocialIcons/SocialIcons.vue",
|
|
47603
47604
|
NexxtSocialMediaCustomTemplate: "components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.vue",
|
|
47604
47605
|
NexxtSocialMediaTemplate: "components/SocialMediaTemplate/SocialMediaTemplate.vue",
|
package/package.json
CHANGED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, ref } from 'vue'
|
|
3
|
+
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
|
|
4
|
+
|
|
5
|
+
type SliderColor = 'blue' | 'green'
|
|
6
|
+
type SliderSize = 'sm' | 'md' | 'lg'
|
|
7
|
+
type SliderVariant = 'filled' | 'plain'
|
|
8
|
+
|
|
9
|
+
interface NexxtSliderProps {
|
|
10
|
+
label?: string
|
|
11
|
+
min?: number
|
|
12
|
+
max?: number
|
|
13
|
+
step?: number
|
|
14
|
+
color?: SliderColor
|
|
15
|
+
size?: SliderSize
|
|
16
|
+
variant?: SliderVariant
|
|
17
|
+
showValue?: boolean
|
|
18
|
+
valueSuffix?: string
|
|
19
|
+
minStepsBetweenThumbs?: number
|
|
20
|
+
disabled?: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
defineOptions({
|
|
24
|
+
name: 'NexxtSlider',
|
|
25
|
+
inheritAttrs: false,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
label,
|
|
30
|
+
min = 0,
|
|
31
|
+
max = 100,
|
|
32
|
+
step = 1,
|
|
33
|
+
color = 'blue',
|
|
34
|
+
size = 'md',
|
|
35
|
+
variant = 'filled',
|
|
36
|
+
showValue = false,
|
|
37
|
+
valueSuffix = '',
|
|
38
|
+
minStepsBetweenThumbs = 0,
|
|
39
|
+
disabled = false,
|
|
40
|
+
} = defineProps<NexxtSliderProps>()
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* One entry per thumb: `[40]` is a plain slider, `[200, 800]` a range. The array is what drives the
|
|
44
|
+
* thumb count, so a range needs no prop of its own.
|
|
45
|
+
*/
|
|
46
|
+
const model = defineModel<number[]>({ default: () => [0] })
|
|
47
|
+
|
|
48
|
+
const rangeColorClasses: Record<SliderColor, string> = {
|
|
49
|
+
blue: 'bg-cornflower-blue-500',
|
|
50
|
+
green: 'bg-green-400',
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Only `plain` colours the thumb — `filled` leaves it white against the coloured track */
|
|
54
|
+
const thumbColorClasses: Record<SliderColor, string> = {
|
|
55
|
+
blue: 'border-cornflower-blue-500 bg-cornflower-blue-500',
|
|
56
|
+
green: 'border-green-400 bg-green-400',
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const thumbFocusClasses: Record<SliderColor, string> = {
|
|
60
|
+
blue: 'focus-visible:outline-cornflower-blue-500',
|
|
61
|
+
green: 'focus-visible:outline-green-400',
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const trackClasses: Record<SliderSize, string> = {
|
|
65
|
+
sm: 'h-0.5',
|
|
66
|
+
md: 'h-1',
|
|
67
|
+
lg: 'h-1.5',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* reka-ui preventDefaults the pointerdown and focuses the thumb from script, so the browser cannot
|
|
72
|
+
* tell a click from a keypress and `:focus-visible` matches on both. Tracking the modality here
|
|
73
|
+
* keeps the ring on keyboard users only. Focus leaving the slider resets it, so tabbing back in
|
|
74
|
+
* still rings.
|
|
75
|
+
*/
|
|
76
|
+
const usingPointer = ref(false)
|
|
77
|
+
|
|
78
|
+
const onFocusOut = (event: FocusEvent) => {
|
|
79
|
+
const next = event.relatedTarget as Node | null
|
|
80
|
+
if (!next || !(event.currentTarget as HTMLElement).contains(next)) usingPointer.value = false
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const displayValue = computed(() =>
|
|
84
|
+
model.value.map((value) => `${value}${valueSuffix}`).join(' – '),
|
|
85
|
+
)
|
|
86
|
+
</script>
|
|
87
|
+
|
|
88
|
+
<template>
|
|
89
|
+
<div class="flex w-full flex-col gap-2">
|
|
90
|
+
<label v-if="label" class="small-normal text-gray-700">
|
|
91
|
+
{{ label }}
|
|
92
|
+
</label>
|
|
93
|
+
|
|
94
|
+
<div class="flex items-center gap-4">
|
|
95
|
+
<SliderRoot
|
|
96
|
+
v-bind="$attrs"
|
|
97
|
+
v-model="model"
|
|
98
|
+
:min="min"
|
|
99
|
+
:max="max"
|
|
100
|
+
:step="step"
|
|
101
|
+
:min-steps-between-thumbs="minStepsBetweenThumbs"
|
|
102
|
+
:disabled="disabled"
|
|
103
|
+
@pointerdown="usingPointer = true"
|
|
104
|
+
@keydown="usingPointer = false"
|
|
105
|
+
@focusout="onFocusOut"
|
|
106
|
+
:class="[
|
|
107
|
+
'relative flex w-full touch-none items-center select-none',
|
|
108
|
+
disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer',
|
|
109
|
+
]"
|
|
110
|
+
>
|
|
111
|
+
<SliderTrack :class="['relative w-full grow rounded-full bg-gray-200', trackClasses[size]]">
|
|
112
|
+
<SliderRange
|
|
113
|
+
:class="[
|
|
114
|
+
'absolute h-full rounded-full',
|
|
115
|
+
variant === 'filled' ? rangeColorClasses[color] : 'bg-transparent',
|
|
116
|
+
]"
|
|
117
|
+
/>
|
|
118
|
+
</SliderTrack>
|
|
119
|
+
|
|
120
|
+
<SliderThumb
|
|
121
|
+
v-for="(_, index) in model"
|
|
122
|
+
:key="index"
|
|
123
|
+
:aria-label="label"
|
|
124
|
+
:class="[
|
|
125
|
+
'block size-4 rounded-full border shadow-sm transition-colors',
|
|
126
|
+
variant === 'filled' ? 'border-gray-200 bg-white' : thumbColorClasses[color],
|
|
127
|
+
usingPointer
|
|
128
|
+
? 'focus-visible:outline-none'
|
|
129
|
+
: [
|
|
130
|
+
'focus-visible:outline-2 focus-visible:outline-offset-2',
|
|
131
|
+
thumbFocusClasses[color],
|
|
132
|
+
],
|
|
133
|
+
]"
|
|
134
|
+
/>
|
|
135
|
+
</SliderRoot>
|
|
136
|
+
|
|
137
|
+
<span
|
|
138
|
+
v-if="showValue"
|
|
139
|
+
class="shrink-0 text-right small-normal whitespace-nowrap text-gray-500"
|
|
140
|
+
:class="model.length > 1 ? 'min-w-24' : 'min-w-12'"
|
|
141
|
+
>
|
|
142
|
+
{{ displayValue }}
|
|
143
|
+
</span>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</template>
|
package/src/components.json
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"NexxtSidebarMenuItem": "components/SidebarMenuItem/SidebarMenuItem.vue",
|
|
35
35
|
"NexxtSkeleton": "components/Skeleton/Skeleton.vue",
|
|
36
36
|
"NexxtSkeletonPropertyCard": "components/SkeletonPropertyCard/SkeletonPropertyCard.vue",
|
|
37
|
+
"NexxtSlider": "components/Slider/Slider.vue",
|
|
37
38
|
"NexxtSocialIcons": "components/SocialIcons/SocialIcons.vue",
|
|
38
39
|
"NexxtSocialMediaCustomTemplate": "components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.vue",
|
|
39
40
|
"NexxtSocialMediaTemplate": "components/SocialMediaTemplate/SocialMediaTemplate.vue",
|
package/src/index.ts
CHANGED
|
@@ -37,6 +37,7 @@ export { default as NexxtSelect } from './components/Select/Select.vue'
|
|
|
37
37
|
export { default as NexxtSidebarMenuItem } from './components/SidebarMenuItem/SidebarMenuItem.vue'
|
|
38
38
|
export { default as NexxtSkeleton } from './components/Skeleton/Skeleton.vue'
|
|
39
39
|
export { default as NexxtSkeletonPropertyCard } from './components/SkeletonPropertyCard/SkeletonPropertyCard.vue'
|
|
40
|
+
export { default as NexxtSlider } from './components/Slider/Slider.vue'
|
|
40
41
|
export { default as NexxtSocialIcons } from './components/SocialIcons/SocialIcons.vue'
|
|
41
42
|
export { default as NexxtSocialMediaCustomTemplate } from './components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.vue'
|
|
42
43
|
export { default as NexxtSocialMediaTemplate } from './components/SocialMediaTemplate/SocialMediaTemplate.vue'
|