@nexxtmove/ui 1.33.0 → 1.34.0
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/atoms/FloatingPanel/FloatingPanel.vue.d.ts +48 -7
- package/dist/components/atoms/PickerItem/PickerItem.vue.d.ts +40 -0
- package/dist/components/atoms/PickerPreview/PickerPreview.vue.d.ts +29 -0
- package/dist/components/editor/molecules/EditorRadius/EditorRadius.vue.d.ts +2 -2
- package/dist/components/molecules/PickerGroup/PickerGroup.vue.d.ts +32 -0
- package/dist/components/molecules/PickerList/PickerList.vue.d.ts +107 -0
- package/dist/components/organisms/ColorPicker/ColorPicker.vue.d.ts +1 -1
- package/dist/components/organisms/PickerPanel/PickerPanel.vue.d.ts +93 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +2299 -1574
- package/dist/nuxt.js +5 -0
- package/package.json +1 -1
- package/src/components/atoms/FloatingPanel/FloatingPanel.vue +280 -20
- package/src/components/atoms/PickerItem/PickerItem.vue +113 -0
- package/src/components/atoms/PickerPreview/PickerPreview.vue +99 -0
- package/src/components/molecules/PickerGroup/PickerGroup.vue +107 -0
- package/src/components/molecules/PickerList/PickerList.vue +649 -0
- package/src/components/organisms/PickerPanel/PickerPanel.vue +267 -0
- package/src/components.json +5 -0
- package/src/index.ts +9 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, useId } from 'vue'
|
|
3
|
+
import { usePreferredReducedMotion } from '@vueuse/core'
|
|
4
|
+
import NexxtIcon from '../../atoms/Icon/Icon.vue'
|
|
5
|
+
|
|
6
|
+
interface NexxtPickerGroupProps {
|
|
7
|
+
/** Heading of the group, and the accessible name of its `role="group"`. */
|
|
8
|
+
label: string
|
|
9
|
+
/**
|
|
10
|
+
* Whether the heading folds the group. `false` turns the heading into a plain label: no
|
|
11
|
+
* chevron, no click handler, no `aria-expanded`.
|
|
12
|
+
*/
|
|
13
|
+
collapsible?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
defineOptions({ name: 'NexxtPickerGroup' })
|
|
17
|
+
|
|
18
|
+
const { label, collapsible = true } = defineProps<NexxtPickerGroupProps>()
|
|
19
|
+
|
|
20
|
+
/** Whether the options are shown. A closed group has its options out of the DOM. */
|
|
21
|
+
const open = defineModel<boolean>('open', { default: true })
|
|
22
|
+
|
|
23
|
+
defineSlots<{
|
|
24
|
+
/** The options: `NexxtPickerItem`s, or anything else with `role="option"`. */
|
|
25
|
+
default(): unknown
|
|
26
|
+
}>()
|
|
27
|
+
|
|
28
|
+
const headingId = useId()
|
|
29
|
+
|
|
30
|
+
const preferredMotion = usePreferredReducedMotion()
|
|
31
|
+
// `motion-reduce:transition-none` alone leaves Vue reading the 120ms off the leaving wrapper, so
|
|
32
|
+
// the options of a "closed" group would linger; without CSS mode they go in the same patch
|
|
33
|
+
const reduced = computed(() => preferredMotion.value === 'reduce')
|
|
34
|
+
|
|
35
|
+
const HEADING_CLASSES = {
|
|
36
|
+
base: 'flex h-7 items-center gap-1.5 rounded-lg px-2 extra-small-semibold tracking-wide text-gray-700 uppercase select-none',
|
|
37
|
+
collapsible: 'cursor-pointer hover:bg-gray-50',
|
|
38
|
+
static: 'cursor-default',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const CHEVRON_CLASSES = {
|
|
42
|
+
base: 'extra-small-normal transition-transform motion-reduce:transition-none',
|
|
43
|
+
open: 'duration-160 ease-out',
|
|
44
|
+
closed: '-rotate-90 duration-120 ease-in',
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const headingClass = computed(() => [
|
|
48
|
+
HEADING_CLASSES.base,
|
|
49
|
+
collapsible ? HEADING_CLASSES.collapsible : HEADING_CLASSES.static,
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
const chevronClass = computed(() => [
|
|
53
|
+
CHEVRON_CLASSES.base,
|
|
54
|
+
open.value ? CHEVRON_CLASSES.open : CHEVRON_CLASSES.closed,
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
// Bound through `v-on`, so a static heading has no click handler at all
|
|
58
|
+
const headingListeners = computed(() =>
|
|
59
|
+
collapsible ? { click: () => (open.value = !open.value) } : {},
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
// Options on their way out can no longer be clicked, and assistive tech skips them
|
|
63
|
+
const onBeforeLeave = (el: Element) => el.setAttribute('inert', '')
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<div
|
|
68
|
+
role="group"
|
|
69
|
+
:aria-labelledby="headingId"
|
|
70
|
+
:aria-expanded="collapsible ? open : undefined"
|
|
71
|
+
class="flex flex-col not-first:mt-2"
|
|
72
|
+
>
|
|
73
|
+
<!-- Not a button and not a tab stop: a listbox may only hold options and groups. The keyboard
|
|
74
|
+
folds a group with ←/→ from the listbox. `mousedown.prevent` keeps focus where it was. -->
|
|
75
|
+
<div role="presentation" :class="headingClass" v-on="headingListeners" @mousedown.prevent>
|
|
76
|
+
<span
|
|
77
|
+
v-if="collapsible"
|
|
78
|
+
class="flex size-3 shrink-0 items-center justify-center text-gray-700"
|
|
79
|
+
>
|
|
80
|
+
<NexxtIcon name="chevron-down" aria-hidden="true" :class="chevronClass" />
|
|
81
|
+
</span>
|
|
82
|
+
<span :id="headingId">{{ label }}</span>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<!-- No row class on the wrapper itself: after entering it is plain `auto`, so a base class
|
|
86
|
+
never fights the from/to classes -->
|
|
87
|
+
<Transition
|
|
88
|
+
:css="!reduced"
|
|
89
|
+
enter-active-class="transition-[grid-template-rows,opacity] duration-160 ease-out motion-reduce:transition-none"
|
|
90
|
+
enter-from-class="grid-rows-[0fr] opacity-0"
|
|
91
|
+
enter-to-class="grid-rows-[1fr] opacity-100"
|
|
92
|
+
leave-active-class="transition-[grid-template-rows,opacity] duration-120 ease-in motion-reduce:transition-none"
|
|
93
|
+
leave-from-class="grid-rows-[1fr] opacity-100"
|
|
94
|
+
leave-to-class="grid-rows-[0fr] opacity-0"
|
|
95
|
+
@before-leave="onBeforeLeave"
|
|
96
|
+
>
|
|
97
|
+
<div v-if="open" class="grid">
|
|
98
|
+
<div class="min-h-0 overflow-hidden">
|
|
99
|
+
<!-- Padding here rather than on the clipping layer, so nothing is left at 0fr -->
|
|
100
|
+
<div class="flex flex-col gap-0.5 pt-0.5">
|
|
101
|
+
<slot />
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</Transition>
|
|
106
|
+
</div>
|
|
107
|
+
</template>
|