@nexxtmove/ui 0.1.62 → 0.1.64
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/index.d.ts +28 -27
- package/dist/index.js +1808 -1687
- package/package.json +1 -1
- package/src/components/Calendar/Calendar.vue +4 -0
- package/src/components/Calendar/_CalendarTimePicker.vue +98 -0
- package/src/components/Calendar/calendar.types.ts +1 -0
- package/src/components/DatePicker/DatePicker.vue +1 -1
- package/src/components/InputField/InputField.vue +38 -4
- package/src/components/Select/Select.vue +2 -2
package/package.json
CHANGED
|
@@ -21,6 +21,7 @@ import CalendarHeader from './_CalendarHeader.vue'
|
|
|
21
21
|
import CalendarDayView from './_CalendarDayView.vue'
|
|
22
22
|
import CalendarMonthView from './_CalendarMonthView.vue'
|
|
23
23
|
import CalendarYearView from './_CalendarYearView.vue'
|
|
24
|
+
import CalendarTimePicker from './_CalendarTimePicker.vue'
|
|
24
25
|
import type { NexxtCalendarProps } from './calendar.types'
|
|
25
26
|
|
|
26
27
|
export type { NexxtCalendarProps }
|
|
@@ -44,6 +45,7 @@ const {
|
|
|
44
45
|
maxDate,
|
|
45
46
|
monthYearPicker = false,
|
|
46
47
|
timezone = 'UTC',
|
|
48
|
+
datetime = false,
|
|
47
49
|
} = defineProps<NexxtCalendarProps>()
|
|
48
50
|
|
|
49
51
|
// ── State ─────────────────────────────────────────────────────────────────────
|
|
@@ -235,5 +237,7 @@ const currentDayTransition = computed(() =>
|
|
|
235
237
|
/>
|
|
236
238
|
</Transition>
|
|
237
239
|
</div>
|
|
240
|
+
|
|
241
|
+
<CalendarTimePicker v-if="datetime" v-model="model" />
|
|
238
242
|
</div>
|
|
239
243
|
</template>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { setHours, setMinutes, getHours, getMinutes } from 'date-fns'
|
|
4
|
+
import NexxtIcon from '../Icon/Icon.vue'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
modelValue: Date | null
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
const emit = defineEmits<{
|
|
11
|
+
(e: 'update:modelValue', value: Date | null): void
|
|
12
|
+
}>()
|
|
13
|
+
|
|
14
|
+
const hours = computed({
|
|
15
|
+
get: () => {
|
|
16
|
+
if (props.modelValue) return getHours(props.modelValue)
|
|
17
|
+
return getHours(new Date())
|
|
18
|
+
},
|
|
19
|
+
set: (val) => {
|
|
20
|
+
const base = props.modelValue || new Date()
|
|
21
|
+
emit('update:modelValue', setHours(base, Number(val)))
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const minutes = computed({
|
|
26
|
+
get: () => {
|
|
27
|
+
if (props.modelValue) return getMinutes(props.modelValue)
|
|
28
|
+
return getMinutes(new Date())
|
|
29
|
+
},
|
|
30
|
+
set: (val) => {
|
|
31
|
+
const base = props.modelValue || new Date()
|
|
32
|
+
emit('update:modelValue', setMinutes(base, Number(val)))
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const pad = (n: number) => n.toString().padStart(2, '0')
|
|
37
|
+
|
|
38
|
+
const incrementHours = () => {
|
|
39
|
+
hours.value = (hours.value + 1) % 24
|
|
40
|
+
}
|
|
41
|
+
const decrementHours = () => {
|
|
42
|
+
hours.value = (hours.value + 23) % 24
|
|
43
|
+
}
|
|
44
|
+
const incrementMinutes = () => {
|
|
45
|
+
minutes.value = (minutes.value + 1) % 60
|
|
46
|
+
}
|
|
47
|
+
const decrementMinutes = () => {
|
|
48
|
+
minutes.value = (minutes.value + 59) % 60
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<div class="flex items-center justify-center gap-4 border-t border-gray-100 pt-4">
|
|
54
|
+
<!-- Hours -->
|
|
55
|
+
<div class="flex flex-col items-center">
|
|
56
|
+
<button
|
|
57
|
+
type="button"
|
|
58
|
+
class="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
|
|
59
|
+
@click="incrementHours"
|
|
60
|
+
>
|
|
61
|
+
<NexxtIcon name="chevron-up" />
|
|
62
|
+
</button>
|
|
63
|
+
<span class="font-medium text-lg text-gray-900 tabular-nums">
|
|
64
|
+
{{ pad(hours) }}
|
|
65
|
+
</span>
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
class="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
|
|
69
|
+
@click="decrementHours"
|
|
70
|
+
>
|
|
71
|
+
<NexxtIcon name="chevron-down" />
|
|
72
|
+
</button>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<span class="mb-1 font-medium text-xl text-gray-400">:</span>
|
|
76
|
+
|
|
77
|
+
<!-- Minutes -->
|
|
78
|
+
<div class="flex flex-col items-center">
|
|
79
|
+
<button
|
|
80
|
+
type="button"
|
|
81
|
+
class="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
|
|
82
|
+
@click="incrementMinutes"
|
|
83
|
+
>
|
|
84
|
+
<NexxtIcon name="chevron-up" />
|
|
85
|
+
</button>
|
|
86
|
+
<span class="font-medium text-lg text-gray-900 tabular-nums">
|
|
87
|
+
{{ pad(minutes) }}
|
|
88
|
+
</span>
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
class="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
|
|
92
|
+
@click="decrementMinutes"
|
|
93
|
+
>
|
|
94
|
+
<NexxtIcon name="chevron-down" />
|
|
95
|
+
</button>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</template>
|
|
@@ -55,7 +55,7 @@ const floatingPlacement = computed(() => anchorToPlacement[props.anchor])
|
|
|
55
55
|
// ── Handlers ──────────────────────────────────────────────────────────────────
|
|
56
56
|
|
|
57
57
|
const handleSelect = () => {
|
|
58
|
-
if (props.autoClose) panelRef.value?.close()
|
|
58
|
+
if (props.autoClose && !props.datetime) panelRef.value?.close()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const onPanelOpen = async () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed, getCurrentInstance } from 'vue'
|
|
2
3
|
import Icon from '../Icon/Icon.vue'
|
|
3
4
|
|
|
4
5
|
const generateId = () => 'input-field-' + Math.random().toString(36).slice(2, 10)
|
|
@@ -20,7 +21,22 @@ export interface NexxtInputFieldProps {
|
|
|
20
21
|
|
|
21
22
|
defineProps<NexxtInputFieldProps>()
|
|
22
23
|
|
|
23
|
-
const modelValue = defineModel<string>()
|
|
24
|
+
const modelValue = defineModel<string | number>()
|
|
25
|
+
|
|
26
|
+
const isNumber = computed(() => {
|
|
27
|
+
const instance = getCurrentInstance()
|
|
28
|
+
return instance?.attrs.type === 'number'
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const increment = () => {
|
|
32
|
+
const current = Number(modelValue.value || 0)
|
|
33
|
+
modelValue.value = current + 1
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const decrement = () => {
|
|
37
|
+
const current = Number(modelValue.value || 0)
|
|
38
|
+
modelValue.value = current - 1
|
|
39
|
+
}
|
|
24
40
|
</script>
|
|
25
41
|
|
|
26
42
|
<template>
|
|
@@ -35,7 +51,7 @@ const modelValue = defineModel<string>()
|
|
|
35
51
|
</label>
|
|
36
52
|
|
|
37
53
|
<div
|
|
38
|
-
class="flex items-center gap-2 overflow-hidden rounded-lg ring transition-colors ease-out focus-within:ring-cornflower-blue-500"
|
|
54
|
+
class="group flex items-center gap-2 overflow-hidden rounded-lg ring transition-colors ease-out focus-within:ring-cornflower-blue-500"
|
|
39
55
|
:class="[error ? 'ring-brick-400' : 'ring-gray-200', { 'pl-3': leftIcon, 'pr-3': rightIcon }]"
|
|
40
56
|
>
|
|
41
57
|
<span v-if="leftIcon" class="flex items-center">
|
|
@@ -47,11 +63,29 @@ const modelValue = defineModel<string>()
|
|
|
47
63
|
v-model="modelValue"
|
|
48
64
|
:placeholder="placeholder"
|
|
49
65
|
v-bind="$attrs"
|
|
50
|
-
class="bg-transparant h-10 w-full min-w-60 text-sm text-gray-900 placeholder-gray-400 focus:outline-none"
|
|
66
|
+
class="bg-transparant h-10 w-full min-w-60 text-sm text-gray-900 placeholder-gray-400 focus:outline-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
|
51
67
|
:class="{ 'pl-3': !leftIcon, 'pr-3': !rightIcon }"
|
|
52
68
|
/>
|
|
53
69
|
<slot name="right">
|
|
54
|
-
<
|
|
70
|
+
<div v-if="isNumber" class="flex flex-col pr-1.5">
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
class="flex h-5 w-8 cursor-pointer items-center justify-center pt-2 text-gray-400 transition-colors group-focus-within:text-gray-950 hover:text-cornflower-blue-600 focus:text-cornflower-blue-600 focus:outline-none"
|
|
74
|
+
aria-label="Verhogen"
|
|
75
|
+
@click="increment"
|
|
76
|
+
>
|
|
77
|
+
<Icon name="chevron-up" class="text-[10px]" aria-hidden="true" />
|
|
78
|
+
</button>
|
|
79
|
+
<button
|
|
80
|
+
type="button"
|
|
81
|
+
class="flex h-5 w-8 cursor-pointer items-center justify-center pb-2 text-gray-400 transition-colors group-focus-within:text-gray-950 hover:text-cornflower-blue-600 focus:text-cornflower-blue-600 focus:outline-none"
|
|
82
|
+
aria-label="Verlagen"
|
|
83
|
+
@click="decrement"
|
|
84
|
+
>
|
|
85
|
+
<Icon name="chevron-down" class="text-[10px]" aria-hidden="true" />
|
|
86
|
+
</button>
|
|
87
|
+
</div>
|
|
88
|
+
<span v-else-if="rightIcon" class="flex items-center">
|
|
55
89
|
<Icon :name="rightIcon" />
|
|
56
90
|
</span>
|
|
57
91
|
</slot>
|
|
@@ -61,7 +61,7 @@ const select = (opt: SelectOption, close: () => void) => {
|
|
|
61
61
|
:aria-expanded="isOpen"
|
|
62
62
|
aria-haspopup="listbox"
|
|
63
63
|
tabindex="0"
|
|
64
|
-
class="flex w-full cursor-pointer items-center gap-2 rounded-lg ring transition-colors ease-out focus:ring-cornflower-blue-500 focus:outline-none"
|
|
64
|
+
class="group flex w-full cursor-pointer items-center gap-2 rounded-lg ring transition-colors ease-out focus:ring-cornflower-blue-500 focus:outline-none"
|
|
65
65
|
:class="[error ? 'ring-brick-400' : 'ring-gray-200', { 'pl-3': leftIcon, 'pr-3': true }]"
|
|
66
66
|
@click="toggle"
|
|
67
67
|
@keydown.enter.prevent="toggle"
|
|
@@ -78,7 +78,7 @@ const select = (opt: SelectOption, close: () => void) => {
|
|
|
78
78
|
</span>
|
|
79
79
|
<NexxtIcon
|
|
80
80
|
name="chevron-down"
|
|
81
|
-
class="shrink-0 text-gray-400 transition-
|
|
81
|
+
class="shrink-0 text-gray-400 transition-all duration-200 group-hover:text-cornflower-blue-600"
|
|
82
82
|
:class="{ 'rotate-180': isOpen }"
|
|
83
83
|
/>
|
|
84
84
|
</div>
|