@nexxtmove/ui 1.1.6 → 1.1.8

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexxtmove/ui",
3
3
  "type": "module",
4
- "version": "1.1.6",
4
+ "version": "1.1.8",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -34,12 +34,12 @@
34
34
  "@eslint/js": "^10.0.1",
35
35
  "@nuxt/kit": "^4.4.8",
36
36
  "@nuxt/schema": "^4.4.4",
37
- "@storybook/addon-a11y": "^10.5.2",
37
+ "@storybook/addon-a11y": "^10.5.4",
38
38
  "@storybook/addon-designs": "^11.1.4",
39
- "@storybook/addon-docs": "^10.5.2",
40
- "@storybook/addon-vitest": "^10.5.2",
41
- "@storybook/builder-vite": "^10.5.2",
42
- "@storybook/vue3-vite": "^10.5.2",
39
+ "@storybook/addon-docs": "^10.5.4",
40
+ "@storybook/addon-vitest": "^10.5.4",
41
+ "@storybook/builder-vite": "^10.5.4",
42
+ "@storybook/vue3-vite": "^10.5.4",
43
43
  "@tailwindcss/vite": "^4.3.1",
44
44
  "@types/node": "^26.0.1",
45
45
  "@types/react": "^19.2.17",
@@ -53,7 +53,7 @@
53
53
  "eslint": "^10.6.0",
54
54
  "eslint-config-prettier": "^10.1.8",
55
55
  "eslint-plugin-prettier": "^5.5.6",
56
- "eslint-plugin-storybook": "10.5.2",
56
+ "eslint-plugin-storybook": "10.5.4",
57
57
  "eslint-plugin-vue": "^10.9.2",
58
58
  "flag-icons": "^7.5.0",
59
59
  "globals": "^17.7.0",
@@ -63,7 +63,7 @@
63
63
  "react": "^19.2.7",
64
64
  "react-dom": "^19.2.7",
65
65
  "remark-frontmatter": "^5.0.0",
66
- "storybook": "^10.5.2",
66
+ "storybook": "^10.5.4",
67
67
  "typescript-eslint": "^8.62.0",
68
68
  "vite": "^8.1.0",
69
69
  "vite-plugin-dts": "^5.0.3",
@@ -8,6 +8,7 @@ interface NexxtProgressBarProps {
8
8
  currentStep: number
9
9
  progressLabel?: string
10
10
  stepTitles?: string[]
11
+ maxInlineSteps?: number
11
12
  }
12
13
 
13
14
  defineOptions({
@@ -22,6 +23,7 @@ const {
22
23
  stepTitles,
23
24
  steps,
24
25
  currentStep,
26
+ maxInlineSteps = 7,
25
27
  } = defineProps<NexxtProgressBarProps>()
26
28
 
27
29
  const isPercentage = computed(() => variant === 'percentage')
@@ -45,6 +47,14 @@ const percentage = computed(() => {
45
47
 
46
48
  const hasTitles = computed(() => !isPercentage.value && Boolean(stepTitles?.length))
47
49
 
50
+ // Reserve the current-step number at the width of the total, so a 9 -> 10
51
+ // transition doesn't shift the "/x" that follows it.
52
+ const stepDigits = computed(() => String(Math.max(steps, 0)).length)
53
+
54
+ // When there are more titles than can comfortably fit side by side, fall back to
55
+ // the compact treatment (current title + "x/y" counter) at every breakpoint.
56
+ const isCompact = computed(() => hasTitles.value && (stepTitles?.length ?? 0) > maxInlineSteps)
57
+
48
58
  watchEffect(() => {
49
59
  if (stepTitles && stepTitles.length !== steps) {
50
60
  console.warn(
@@ -89,24 +99,37 @@ watchEffect(() => {
89
99
  </div>
90
100
  <div
91
101
  v-if="hasTitles"
92
- class="flex items-center small-normal tabular-nums @md:hidden"
102
+ class="flex items-center gap-0.5 small-normal tabular-nums"
103
+ :class="isCompact ? '' : '@md:hidden'"
93
104
  aria-hidden="true"
94
105
  >
95
- <AnimatedNumber :value="displayStep" />
96
- <span>/{{ steps }}</span>
106
+ <span class="flex justify-end" :style="{ minWidth: `${stepDigits}ch` }">
107
+ <AnimatedNumber :value="displayStep" />
108
+ </span>
109
+ <span>/</span>
110
+ <span>{{ steps }}</span>
97
111
  </div>
98
112
  </div>
99
113
  <ol
100
114
  v-if="hasTitles"
101
- class="flex justify-between @max-md:order-first @max-md:justify-center"
115
+ class="flex @max-md:order-first"
116
+ :class="isCompact ? 'order-first justify-center' : 'justify-between @max-md:justify-center'"
102
117
  aria-label="Progress steps"
103
118
  >
104
119
  <li
105
120
  v-for="(title, index) in stepTitles"
106
121
  :key="title"
107
- class="rounded-xs transition-colors duration-500 focus-visible:outline-3 @max-md:hidden @max-md:body-normal @min-md:small-normal"
122
+ class="rounded-xs transition-colors duration-500 focus-visible:outline-3"
108
123
  :class="[
109
- index === clampedStep ? 'text-sapphire-500 @max-md:inline' : '',
124
+ isCompact
125
+ ? index === clampedStep
126
+ ? 'body-normal'
127
+ : 'hidden'
128
+ : [
129
+ '@max-md:body-normal @min-md:small-normal',
130
+ index === clampedStep ? '@max-md:inline' : '@max-md:hidden',
131
+ ],
132
+ index === clampedStep ? 'text-sapphire-500' : '',
110
133
  index < clampedStep ? 'cursor-pointer duration-200! hover:text-sapphire-400' : '',
111
134
  ]"
112
135
  :aria-current="index === clampedStep ? 'step' : undefined"
@@ -3,10 +3,12 @@ import type { IconName } from '@awesome.me/kit-37b149f3ef/icons'
3
3
  import Icon from '../Icon/Icon.vue'
4
4
 
5
5
  type SwitchColor = 'blue' | 'green'
6
+ type SwitchSize = 'sm' | 'md' | 'lg'
6
7
 
7
8
  interface NexxtSwitchProps {
8
9
  labelPosition?: 'before' | 'after'
9
10
  color?: SwitchColor
11
+ size?: SwitchSize
10
12
  iconOn?: IconName
11
13
  iconOff?: IconName
12
14
  }
@@ -16,7 +18,13 @@ defineOptions({
16
18
  inheritAttrs: false,
17
19
  })
18
20
 
19
- const { labelPosition = 'after', color = 'blue', iconOn, iconOff } = defineProps<NexxtSwitchProps>()
21
+ const {
22
+ labelPosition = 'after',
23
+ color = 'blue',
24
+ size = 'lg',
25
+ iconOn,
26
+ iconOff,
27
+ } = defineProps<NexxtSwitchProps>()
20
28
 
21
29
  const model = defineModel<boolean>()
22
30
 
@@ -24,12 +32,36 @@ const checkedColorClasses: Record<SwitchColor, string> = {
24
32
  blue: 'border-cornflower-blue-500 bg-cornflower-blue-500',
25
33
  green: 'border-green-400 bg-green-400',
26
34
  }
35
+
36
+ const trackClasses: Record<SwitchSize, string> = {
37
+ sm: 'h-5 w-9',
38
+ md: 'h-6 w-11',
39
+ lg: 'h-8 w-15',
40
+ }
41
+
42
+ const knobClasses: Record<SwitchSize, string> = {
43
+ sm: 'top-0.5 left-0.5 h-3.5 w-3.5',
44
+ md: 'top-0.5 left-0.5 h-4.5 w-4.5',
45
+ lg: 'top-0.75 left-0.75 h-6 w-6',
46
+ }
47
+
48
+ const knobTranslateClasses: Record<SwitchSize, string> = {
49
+ sm: 'translate-x-4',
50
+ md: 'translate-x-5',
51
+ lg: 'translate-x-7',
52
+ }
53
+
54
+ const iconSizeClasses: Record<SwitchSize, string> = {
55
+ sm: 'text-[8px]',
56
+ md: 'text-[10px]',
57
+ lg: 'text-xs',
58
+ }
27
59
  </script>
28
60
 
29
61
  <template>
30
62
  <label class="inline-flex cursor-pointer items-center gap-2">
31
63
  <slot v-if="labelPosition === 'before'" />
32
- <span class="relative inline-block h-8 w-15">
64
+ <span :class="['relative inline-block', trackClasses[size]]">
33
65
  <input v-bind="$attrs" type="checkbox" class="peer sr-only" v-model="model" />
34
66
  <span
35
67
  :class="[
@@ -39,18 +71,29 @@ const checkedColorClasses: Record<SwitchColor, string> = {
39
71
  >
40
72
  <span
41
73
  :class="[
42
- 'absolute top-0.75 left-0.75 h-6 w-6 rounded-full bg-white transition-transform duration-400',
43
- model && 'translate-x-7',
74
+ 'absolute rounded-full bg-white transition-transform duration-400',
75
+ knobClasses[size],
76
+ model && knobTranslateClasses[size],
44
77
  ]"
45
78
  />
46
79
  <span
47
80
  :class="[
48
- 'absolute top-0.75 left-0.75 flex h-6 w-6 items-center justify-center rounded-full bg-white transition-transform duration-300',
49
- model && 'translate-x-7',
81
+ 'absolute flex items-center justify-center rounded-full bg-white transition-transform duration-300',
82
+ knobClasses[size],
83
+ model && knobTranslateClasses[size],
50
84
  ]"
51
85
  >
52
- <Icon v-if="model && iconOn" :name="iconOn" type="solid" class="text-xs text-gray-600" />
53
- <Icon v-else-if="!model && iconOff" :name="iconOff" class="text-xs text-gray-600" />
86
+ <Icon
87
+ v-if="model && iconOn"
88
+ :name="iconOn"
89
+ type="solid"
90
+ :class="['text-gray-600', iconSizeClasses[size]]"
91
+ />
92
+ <Icon
93
+ v-else-if="!model && iconOff"
94
+ :name="iconOff"
95
+ :class="['text-gray-600', iconSizeClasses[size]]"
96
+ />
54
97
  </span>
55
98
  </span>
56
99
  </span>