@nexxtmove/ui 1.0.2 → 1.0.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
@@ -42958,6 +42958,7 @@ var Vw, Hw, Uw, Ww, Gw, Kw = t((() => {
42958
42958
  NexxtIcon: "components/Icon/Icon.vue",
42959
42959
  NexxtInfoBlock: "components/InfoBlock/InfoBlock.vue",
42960
42960
  NexxtInputField: "components/InputField/InputField.vue",
42961
+ NexxtInputSelect: "components/InputSelect/InputSelect.vue",
42961
42962
  NexxtModal: "components/Modal/Modal.vue",
42962
42963
  NexxtPagination: "components/Pagination/Pagination.vue",
42963
42964
  NexxtPresenceIndicator: "components/PresenceIndicator/PresenceIndicator.vue",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexxtmove/ui",
3
3
  "type": "module",
4
- "version": "1.0.2",
4
+ "version": "1.0.3",
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.4",
36
36
  "@nuxt/schema": "^4.4.4",
37
- "@storybook/addon-a11y": "^10.3.6",
37
+ "@storybook/addon-a11y": "^10.4.0",
38
38
  "@storybook/addon-designs": "^11.1.3",
39
- "@storybook/addon-docs": "^10.3.6",
40
- "@storybook/addon-vitest": "^10.3.6",
41
- "@storybook/builder-vite": "^10.3.6",
42
- "@storybook/vue3-vite": "^10.3.6",
39
+ "@storybook/addon-docs": "^10.4.0",
40
+ "@storybook/addon-vitest": "^10.4.0",
41
+ "@storybook/builder-vite": "^10.4.0",
42
+ "@storybook/vue3-vite": "^10.4.0",
43
43
  "@tailwindcss/vite": "^4.2.4",
44
44
  "@types/node": "^25.6.0",
45
45
  "@types/react": "^19.2.14",
@@ -53,7 +53,7 @@
53
53
  "eslint": "^10.2.1",
54
54
  "eslint-config-prettier": "^10.1.8",
55
55
  "eslint-plugin-prettier": "^5.5.5",
56
- "eslint-plugin-storybook": "10.3.6",
56
+ "eslint-plugin-storybook": "10.4.0",
57
57
  "eslint-plugin-vue": "^10.9.0",
58
58
  "globals": "^17.5.0",
59
59
  "jsdom": "^29.1.0",
@@ -62,7 +62,7 @@
62
62
  "react": "^19.2.5",
63
63
  "react-dom": "^19.2.5",
64
64
  "remark-frontmatter": "^5.0.0",
65
- "storybook": "^10.3.6",
65
+ "storybook": "^10.4.0",
66
66
  "typescript-eslint": "^8.59.1",
67
67
  "vite": "^8.0.10",
68
68
  "vite-plugin-dts": "^4.5.4",
@@ -4,24 +4,30 @@ import NexxtIcon from '../Icon/Icon.vue'
4
4
  interface NexxtAnnouncementProps {
5
5
  color?: string
6
6
  text_color?: string
7
+ icon?: InstanceType<typeof NexxtIcon>['name']
8
+ showHideButton?: boolean
7
9
  }
8
10
 
9
- const { color = 'blue', text_color = 'white' } = defineProps<NexxtAnnouncementProps>()
11
+ const {
12
+ color = 'blue',
13
+ text_color = 'white',
14
+ icon = 'megaphone',
15
+ showHideButton = true,
16
+ } = defineProps<NexxtAnnouncementProps>()
10
17
 
11
18
  const emit = defineEmits<{ hide: [] }>()
12
19
  </script>
13
20
 
14
21
  <template>
15
22
  <div
16
- class="flex items-center justify-between overflow-hidden rounded-md px-4 py-3"
23
+ class="grid items-center gap-x-3 overflow-hidden rounded-md px-4 py-3"
24
+ :class="showHideButton ? 'grid-cols-[auto_1fr_auto]' : 'grid-cols-[auto_1fr]'"
17
25
  :style="{ background: color, color: text_color }"
18
26
  >
19
- <div class="flex items-center gap-3">
20
- <NexxtIcon class="text-lg" name="megaphone" />
21
- <slot />
22
- </div>
23
-
27
+ <NexxtIcon class="text-lg" :name="icon" />
28
+ <slot />
24
29
  <button
30
+ v-if="showHideButton"
25
31
  type="button"
26
32
  class="cursor-pointer text-2xl leading-none opacity-70 hover:opacity-100"
27
33
  @click="emit('hide')"
@@ -0,0 +1,139 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue'
3
+ import NexxtIcon from '../Icon/Icon.vue'
4
+ import NexxtFloatingPanel from '../FloatingPanel/FloatingPanel.vue'
5
+ import type Icon from '../Icon/Icon.vue'
6
+ import type { SelectOption } from '../Select/Select.vue'
7
+
8
+ export type { SelectOption }
9
+
10
+ const generateId = () => 'input-select-' + Math.random().toString(36).slice(2, 10)
11
+ const fieldId = generateId()
12
+ const selectId = generateId()
13
+
14
+ defineOptions({ name: 'NexxtInputSelect' })
15
+
16
+ export interface NexxtInputSelectProps {
17
+ options: SelectOption[]
18
+ label?: string
19
+ placeholder?: string
20
+ selectPlaceholder?: string
21
+ selectPosition?: 'before' | 'after'
22
+ error?: boolean
23
+ errorMessage?: string
24
+ required?: boolean
25
+ leftIcon?: InstanceType<typeof Icon>['name']
26
+ }
27
+
28
+ const props = withDefaults(defineProps<NexxtInputSelectProps>(), {
29
+ selectPlaceholder: 'Selecteer...',
30
+ selectPosition: 'after',
31
+ })
32
+
33
+ const getLabel = (opt: SelectOption) => (typeof opt === 'string' ? opt : opt.label)
34
+ const getValue = (opt: SelectOption): string | number => (typeof opt === 'string' ? opt : opt.value)
35
+
36
+ const inputModel = defineModel<string | number>('input')
37
+ const selectModel = defineModel<string | number | null>('select', { default: null })
38
+
39
+ const selectedLabel = computed(() => {
40
+ if (selectModel.value === null || selectModel.value === undefined) return null
41
+ const found = props.options.find((opt) => getValue(opt) === selectModel.value)
42
+ return found ? getLabel(found) : null
43
+ })
44
+
45
+ const select = (opt: SelectOption, close: () => void) => {
46
+ selectModel.value = getValue(opt)
47
+ close()
48
+ }
49
+ </script>
50
+
51
+ <template>
52
+ <div class="inline-flex flex-col gap-1">
53
+ <label
54
+ v-if="label"
55
+ class="text-color-gray-700 justify-start body-normal text-sm"
56
+ :for="fieldId"
57
+ >
58
+ {{ label }}
59
+ <span v-if="required" class="text-brick-500">*</span>
60
+ </label>
61
+
62
+ <div
63
+ class="group flex items-center overflow-hidden rounded-lg ring transition-colors ease-out focus-within:ring-cornflower-blue-500"
64
+ :class="[
65
+ error ? 'ring-brick-400' : 'ring-gray-200',
66
+ selectPosition === 'after' ? 'flex-row-reverse' : 'flex-row',
67
+ ]"
68
+ >
69
+ <NexxtFloatingPanel :placement="selectPosition === 'after' ? 'bottom-end' : 'bottom-start'">
70
+ <template #trigger="{ isOpen, toggle }">
71
+ <div
72
+ :id="selectId"
73
+ role="combobox"
74
+ :aria-expanded="isOpen"
75
+ aria-haspopup="listbox"
76
+ tabindex="0"
77
+ class="flex h-10 shrink-0 cursor-pointer items-center gap-1.5 px-3 text-sm transition-colors focus:outline-none"
78
+ :class="[
79
+ selectedLabel ? 'text-gray-900' : 'text-gray-400',
80
+ selectPosition === 'after' ? 'border-l border-gray-200' : 'border-r border-gray-200',
81
+ ]"
82
+ @click="toggle"
83
+ @keydown.enter.prevent="toggle"
84
+ @keydown.space.prevent="toggle"
85
+ >
86
+ <NexxtIcon v-if="leftIcon" :name="leftIcon" class="text-gray-400" />
87
+ <span>{{ selectedLabel ?? selectPlaceholder }}</span>
88
+ <NexxtIcon
89
+ name="chevron-down"
90
+ class="shrink-0 text-gray-400 transition-all duration-200"
91
+ :class="{ 'rotate-180': isOpen }"
92
+ />
93
+ </div>
94
+ </template>
95
+
96
+ <template #content="{ close }">
97
+ <ul
98
+ role="listbox"
99
+ class="overflow-hidden rounded-lg bg-white shadow-xs ring ring-gray-100"
100
+ >
101
+ <li
102
+ v-for="opt in options"
103
+ :key="getValue(opt)"
104
+ role="option"
105
+ :aria-selected="selectModel === getValue(opt)"
106
+ class="flex cursor-pointer items-center justify-between px-4 py-3 text-sm text-gray-900 transition-colors duration-150 hover:bg-gray-50 hover:text-purple-600"
107
+ :class="{ 'font-medium text-cornflower-blue-600': selectModel === getValue(opt) }"
108
+ @click="select(opt, close)"
109
+ >
110
+ {{ getLabel(opt) }}
111
+ <NexxtIcon v-if="selectModel === getValue(opt)" name="check" class="text-xs" />
112
+ </li>
113
+ </ul>
114
+ </template>
115
+ </NexxtFloatingPanel>
116
+
117
+ <input
118
+ :id="fieldId"
119
+ v-model="inputModel"
120
+ :placeholder="placeholder"
121
+ v-bind="$attrs"
122
+ class="bg-transparant h-10 w-full min-w-40 px-3 text-sm text-gray-900 placeholder-gray-400 focus:outline-none"
123
+ />
124
+ </div>
125
+
126
+ <Transition
127
+ enter-active-class="transition-all duration-200 ease-out"
128
+ enter-from-class="opacity-0 -translate-y-1"
129
+ enter-to-class="opacity-100 translate-y-0"
130
+ leave-active-class="transition-all duration-150 ease-in"
131
+ leave-from-class="opacity-100 translate-y-0"
132
+ leave-to-class="opacity-0 -translate-y-1"
133
+ >
134
+ <p v-if="error && errorMessage" class="text-sm text-brick-400">
135
+ {{ errorMessage }}
136
+ </p>
137
+ </Transition>
138
+ </div>
139
+ </template>
@@ -20,6 +20,7 @@
20
20
  "NexxtIcon": "components/Icon/Icon.vue",
21
21
  "NexxtInfoBlock": "components/InfoBlock/InfoBlock.vue",
22
22
  "NexxtInputField": "components/InputField/InputField.vue",
23
+ "NexxtInputSelect": "components/InputSelect/InputSelect.vue",
23
24
  "NexxtModal": "components/Modal/Modal.vue",
24
25
  "NexxtPagination": "components/Pagination/Pagination.vue",
25
26
  "NexxtPresenceIndicator": "components/PresenceIndicator/PresenceIndicator.vue",
package/src/index.ts CHANGED
@@ -20,6 +20,7 @@ export { default as NexxtHeader } from './components/Header/Header.vue'
20
20
  export { default as NexxtIcon } from './components/Icon/Icon.vue'
21
21
  export { default as NexxtInfoBlock } from './components/InfoBlock/InfoBlock.vue'
22
22
  export { default as NexxtInputField } from './components/InputField/InputField.vue'
23
+ export { default as NexxtInputSelect } from './components/InputSelect/InputSelect.vue'
23
24
  export { default as NexxtModal } from './components/Modal/Modal.vue'
24
25
  export { default as NexxtPagination } from './components/Pagination/Pagination.vue'
25
26
  export { default as NexxtPresenceIndicator } from './components/PresenceIndicator/PresenceIndicator.vue'