@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/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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexxtmove/ui",
3
3
  "type": "module",
4
- "version": "1.2.2",
4
+ "version": "1.2.3",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -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>
@@ -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'