pxd 0.0.33 → 0.0.35
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/active-graph/index.vue +7 -7
- package/dist/components/badge/index.vue +1 -1
- package/dist/components/browser/index.vue +1 -1
- package/dist/components/button/index.vue +2 -2
- package/dist/components/carousel-group/index.vue +1 -1
- package/dist/components/choicebox/index.vue +1 -1
- package/dist/components/choicebox-group/index.vue +1 -1
- package/dist/components/config-provider/index.vue +1 -1
- package/dist/components/countdown/index.vue +2 -2
- package/dist/components/drawer/index.vue +84 -63
- package/dist/components/drawer/index.vue.d.ts +9 -8
- package/dist/components/list/index.vue +18 -20
- package/dist/components/list-item/index.vue +28 -47
- package/dist/components/list-item/index.vue.d.ts +11 -9
- package/dist/components/material/index.vue +1 -1
- package/dist/components/message/index.vue +144 -23
- package/dist/components/message/index.vue.d.ts +62 -1
- package/dist/components/modal/index.vue +12 -10
- package/dist/components/modal/index.vue.d.ts +7 -6
- package/dist/components/note/index.vue +1 -1
- package/dist/components/overlay/index.vue +32 -13
- package/dist/components/overlay/index.vue.d.ts +1 -0
- package/dist/components/popover/index.vue +47 -61
- package/dist/components/popover/index.vue.d.ts +2 -0
- package/dist/components/resizable/index.vue +2 -2
- package/dist/components/scrollable/index.vue +8 -5
- package/dist/components/snippet/index.vue +2 -2
- package/dist/components/stack/index.vue +1 -1
- package/dist/components/status-dot/index.vue +5 -5
- package/dist/components/teleport/index.vue +36 -34
- package/dist/components/text/index.vue +1 -1
- package/dist/components/theme-switcher/index.vue +1 -1
- package/dist/components/tooltip/index.vue +1 -1
- package/dist/composables/use-color-scheme.js +5 -1
- package/dist/composables/use-countdown.d.ts +1 -1
- package/dist/composables/use-countdown.js +2 -2
- package/dist/composables/use-delay-change.d.ts +3 -3
- package/dist/composables/use-delay-change.js +8 -8
- package/dist/composables/use-focus-trap.d.ts +2 -3
- package/dist/composables/use-focus-trap.js +7 -8
- package/dist/composables/use-media-query.js +4 -1
- package/dist/composables/use-message.d.ts +4 -37
- package/dist/composables/use-message.js +8 -140
- package/dist/composables/use-pointer-gesture.d.ts +9 -3
- package/dist/composables/use-pointer-gesture.js +25 -21
- package/dist/composables/use-virtual-list.d.ts +1 -0
- package/dist/composables/use-virtual-list.js +28 -21
- package/dist/contexts/list.d.ts +1 -0
- package/dist/contexts/list.js +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/styles/styles.css +1 -1
- package/dist/styles/tw.css +8 -3
- package/dist/types/components/list.d.ts +2 -1
- package/dist/types/shared/utils.d.ts +3 -0
- package/dist/utils/format.js +1 -1
- package/package.json +1 -1
|
@@ -206,8 +206,8 @@ let tbodyRect;
|
|
|
206
206
|
const tbodyRef = shallowRef();
|
|
207
207
|
const {
|
|
208
208
|
value: showTooltip,
|
|
209
|
-
|
|
210
|
-
|
|
209
|
+
setValue: setShowTooltip,
|
|
210
|
+
setValueDelay: setShowTooltipDelay
|
|
211
211
|
} = useDelayChange(false, 500);
|
|
212
212
|
const tooltipInfo = shallowRef({});
|
|
213
213
|
const formatTooltipText = computed(() => {
|
|
@@ -218,25 +218,25 @@ const formatTooltipText = computed(() => {
|
|
|
218
218
|
return "";
|
|
219
219
|
});
|
|
220
220
|
function onMouseLeave() {
|
|
221
|
-
|
|
221
|
+
setShowTooltip(false);
|
|
222
222
|
tooltipInfo.value = {};
|
|
223
223
|
tbodyRect = null;
|
|
224
224
|
}
|
|
225
225
|
async function onMouseOver(ev) {
|
|
226
226
|
const targetEl = ev.target;
|
|
227
227
|
if (targetEl.tagName !== "TD") {
|
|
228
|
-
|
|
228
|
+
setShowTooltipDelay(false);
|
|
229
229
|
return;
|
|
230
230
|
}
|
|
231
231
|
const date = targetEl.dataset.date;
|
|
232
232
|
if (!date) {
|
|
233
|
-
|
|
233
|
+
setShowTooltip(false);
|
|
234
234
|
return;
|
|
235
235
|
}
|
|
236
236
|
if (!tbodyRect) {
|
|
237
237
|
tbodyRect = tbodyRef.value.getBoundingClientRect();
|
|
238
238
|
}
|
|
239
|
-
|
|
239
|
+
setShowTooltip(true);
|
|
240
240
|
const rect = targetEl.getBoundingClientRect();
|
|
241
241
|
let top = rect.top - tbodyRect.top - CELL_SIZE;
|
|
242
242
|
if (props.graphOnly) {
|
|
@@ -322,7 +322,7 @@ onBeforeUnmount(() => {
|
|
|
322
322
|
</tbody>
|
|
323
323
|
</table>
|
|
324
324
|
|
|
325
|
-
<Transition name="pxd-transition--fade">
|
|
325
|
+
<Transition name="pxd-transition--fade" mode="out-in" appear>
|
|
326
326
|
<div
|
|
327
327
|
v-if="showTooltip"
|
|
328
328
|
class="pxd-active-graph--tooltip left-0 top-0 px-2 py-1 pointer-events-none absolute z-1 w-max rounded-sm bg-gray-1000 text-[13px] text-gray-100 duration-50 will-change-transform motion-safe:transition-transform"
|
|
@@ -42,7 +42,7 @@ const { isCopied, copyText } = useCopyClick();
|
|
|
42
42
|
|
|
43
43
|
<PButton variant="ghost" size="xs" shape="rounded" class="size-6" icon @click="copyText(address)">
|
|
44
44
|
<Transition name="pxd-transition--fade-scale" mode="out-in">
|
|
45
|
-
<
|
|
45
|
+
<Component :is="isCopied ? CheckIcon : CopyIcon" class="text-sm text-foreground-secondary" />
|
|
46
46
|
</Transition>
|
|
47
47
|
</PButton>
|
|
48
48
|
</div>
|
|
@@ -54,7 +54,7 @@ const ALIGNMENTS = {
|
|
|
54
54
|
center: "justify-center",
|
|
55
55
|
right: "justify-end"
|
|
56
56
|
};
|
|
57
|
-
const DISABLED_CLASS_NAMES = "is-disabled bg-gray-100 hover:bg-gray-100 active:bg-gray-100 disabled:cursor-not-allowed text-gray-700 border-gray-300";
|
|
57
|
+
const DISABLED_CLASS_NAMES = "is-disabled disabled:bg-gray-100 hover:bg-gray-100 active:bg-gray-100 disabled:cursor-not-allowed disabled:text-gray-700 disabled:border-gray-300";
|
|
58
58
|
const config = useConfigProvider();
|
|
59
59
|
const computedDisabled = computed(() => isTruthyProp(props.disabled) || isTruthyProp(props.loading));
|
|
60
60
|
const computedClass = computed(() => {
|
|
@@ -89,7 +89,7 @@ function onButtonDblClick(event) {
|
|
|
89
89
|
</script>
|
|
90
90
|
|
|
91
91
|
<template>
|
|
92
|
-
<
|
|
92
|
+
<Component
|
|
93
93
|
:is="as"
|
|
94
94
|
role="button"
|
|
95
95
|
:class="computedClass"
|
|
@@ -29,7 +29,7 @@ let autoPlayRafId = null;
|
|
|
29
29
|
let autoPlaySession = 0;
|
|
30
30
|
let isPointerEntering = false;
|
|
31
31
|
const carousels = ref([]);
|
|
32
|
-
const sliderRef = shallowRef(
|
|
32
|
+
const sliderRef = shallowRef();
|
|
33
33
|
const virtualIndex = shallowRef(props.index);
|
|
34
34
|
const correctIndex = computed(() => {
|
|
35
35
|
const index = virtualIndex.value;
|
|
@@ -28,7 +28,7 @@ const computedAttrs = computed(() => {
|
|
|
28
28
|
</script>
|
|
29
29
|
|
|
30
30
|
<template>
|
|
31
|
-
<
|
|
31
|
+
<Component :is="renderComponent" v-model="choiceboxModelValue" v-bind="computedAttrs">
|
|
32
32
|
<div class="gap-1 flex flex-col">
|
|
33
33
|
<span class="pxd-choicebox--label font-medium">
|
|
34
34
|
<slot name="label">
|
|
@@ -21,7 +21,7 @@ const emits = defineEmits(["change", "reset", "finish"]);
|
|
|
21
21
|
dayjs.extend(durationPlugin);
|
|
22
22
|
dayjs.extend(millisecondTokenPlugin);
|
|
23
23
|
const {
|
|
24
|
-
|
|
24
|
+
stop,
|
|
25
25
|
reset,
|
|
26
26
|
timestamp
|
|
27
27
|
} = useCountdown(props, emits);
|
|
@@ -40,7 +40,7 @@ const displayTimes = computed(() => {
|
|
|
40
40
|
return time;
|
|
41
41
|
});
|
|
42
42
|
onBeforeUnmount(() => {
|
|
43
|
-
|
|
43
|
+
stop();
|
|
44
44
|
});
|
|
45
45
|
defineExpose({
|
|
46
46
|
reset,
|
|
@@ -14,65 +14,50 @@ defineOptions({
|
|
|
14
14
|
}
|
|
15
15
|
});
|
|
16
16
|
const props = defineProps({
|
|
17
|
-
size: { type: [Number, String], required: false, default: "30%" },
|
|
18
17
|
title: { type: [String, Number, Array, null], required: false },
|
|
19
18
|
subtitle: { type: [String, Number, Array, null], required: false },
|
|
19
|
+
size: { type: [Number, String], required: false },
|
|
20
|
+
pending: { type: Boolean, required: false },
|
|
21
|
+
position: { type: String, required: false, default: "right" },
|
|
20
22
|
modelValue: { type: Boolean, required: false, default: false },
|
|
21
|
-
headerStyle: { type: Boolean, required: false, default: false },
|
|
22
|
-
footerStyle: { type: Boolean, required: false, default: true },
|
|
23
23
|
appendToBody: { type: Boolean, required: false, default: true },
|
|
24
|
+
headerStylize: { type: Boolean, required: false, default: false },
|
|
25
|
+
footerStylize: { type: Boolean, required: false, default: true },
|
|
26
|
+
drawerClass: { type: [String, Array, Object], required: false },
|
|
24
27
|
closeOnPressEscape: { type: Boolean, required: false, default: true },
|
|
25
|
-
closeOnClickOverlay: { type: Boolean, required: false, default: true }
|
|
26
|
-
position: { type: String, required: false, default: "right" }
|
|
28
|
+
closeOnClickOverlay: { type: Boolean, required: false, default: true }
|
|
27
29
|
});
|
|
28
30
|
const emits = defineEmits(["open", "close", "click-outside", "update:modelValue"]);
|
|
29
31
|
const drawerRef = shallowRef();
|
|
30
32
|
const isVisible = useModelValue(props, emits);
|
|
31
33
|
useFocusTrap(drawerRef);
|
|
32
|
-
const
|
|
34
|
+
const ensurePosition = computed(() => {
|
|
33
35
|
const { position } = props;
|
|
34
36
|
if (["top", "bottom", "left", "right"].includes(position)) {
|
|
35
37
|
return position;
|
|
36
38
|
}
|
|
37
39
|
return "right";
|
|
38
40
|
});
|
|
39
|
-
const transitionName = computed(() => {
|
|
40
|
-
return `pxd-transition--drawer-slide-${ensureCorrectPosition.value}`;
|
|
41
|
-
});
|
|
42
|
-
const computedClass = computed(() => {
|
|
43
|
-
const classes = ["pxd-drawer translate-z-0 fixed z-10 flex flex-col bg-background-100 shadow-border-modal outline-none"];
|
|
44
|
-
switch (ensureCorrectPosition.value) {
|
|
45
|
-
case "top":
|
|
46
|
-
classes.push("top-0", "left-0", "right-0");
|
|
47
|
-
break;
|
|
48
|
-
case "right":
|
|
49
|
-
classes.push("top-0", "right-0", "bottom-0");
|
|
50
|
-
break;
|
|
51
|
-
case "bottom":
|
|
52
|
-
classes.push("bottom-0", "left-0", "right-0");
|
|
53
|
-
break;
|
|
54
|
-
case "left":
|
|
55
|
-
classes.push("top-0", "left-0", "bottom-0");
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
return classes.join(" ");
|
|
59
|
-
});
|
|
41
|
+
const transitionName = computed(() => `pxd-transition--drawer-${ensurePosition.value}`);
|
|
60
42
|
const computedStyle = computed(() => {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
43
|
+
const styles = {};
|
|
44
|
+
if (props.size) {
|
|
45
|
+
styles["--size"] = getCssUnitValue(props.size);
|
|
46
|
+
}
|
|
47
|
+
return styles;
|
|
65
48
|
});
|
|
66
49
|
function onOverlayClick(ev) {
|
|
67
50
|
emits("click-outside", ev);
|
|
68
|
-
if (!props.closeOnClickOverlay) {
|
|
51
|
+
if (!props.closeOnClickOverlay || props.pending) {
|
|
69
52
|
return;
|
|
70
53
|
}
|
|
71
|
-
closeDrawer();
|
|
72
|
-
}
|
|
73
|
-
function closeDrawer() {
|
|
74
54
|
isVisible.value = false;
|
|
75
|
-
|
|
55
|
+
}
|
|
56
|
+
function onUpdateModelValue(visible) {
|
|
57
|
+
if (!visible && props.pending) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
isVisible.value = visible;
|
|
76
61
|
}
|
|
77
62
|
watch(() => isVisible.value, (visible) => {
|
|
78
63
|
if (visible) {
|
|
@@ -85,24 +70,27 @@ watch(() => isVisible.value, (visible) => {
|
|
|
85
70
|
|
|
86
71
|
<template>
|
|
87
72
|
<POverlay
|
|
88
|
-
|
|
73
|
+
:model-value="isVisible"
|
|
89
74
|
:append-to-body="appendToBody"
|
|
90
75
|
:close-on-press-escape="closeOnPressEscape"
|
|
76
|
+
:update:model-value="onUpdateModelValue"
|
|
91
77
|
@click="onOverlayClick"
|
|
92
78
|
>
|
|
93
|
-
<Transition :name="transitionName" mode="out-in">
|
|
79
|
+
<Transition :name="transitionName" mode="out-in" appear>
|
|
94
80
|
<div
|
|
95
81
|
v-if="isVisible"
|
|
96
82
|
ref="drawerRef"
|
|
97
83
|
aria-modal="true"
|
|
98
84
|
role="dialog"
|
|
99
85
|
tabindex="-1"
|
|
100
|
-
|
|
86
|
+
class="pxd-drawer translate-z-0 sm:[--w:30vw] sm:[--h:30vw] fixed z-10 flex max-h-full max-w-full flex-col bg-background-100 shadow-border-modal outline-none"
|
|
87
|
+
:class="drawerClass"
|
|
101
88
|
:style="computedStyle"
|
|
89
|
+
:data-position="ensurePosition"
|
|
102
90
|
>
|
|
103
91
|
<header
|
|
104
|
-
class="pxd-drawer--header p-6 sm:
|
|
105
|
-
:class="{ 'border-b bg-background-200 dark:bg-background-100':
|
|
92
|
+
class="pxd-drawer--header p-6 sm:pb-4 relative shrink-0 empty:py-3"
|
|
93
|
+
:class="{ 'sm:pt-4 border-b bg-background-200 dark:bg-background-100': headerStylize }"
|
|
106
94
|
>
|
|
107
95
|
<h3 v-if="$slots.title || title" class="text-xl font-semibold tracking-tight">
|
|
108
96
|
<slot name="title">
|
|
@@ -119,17 +107,18 @@ watch(() => isVisible.value, (visible) => {
|
|
|
119
107
|
|
|
120
108
|
<PScrollable
|
|
121
109
|
v-if="$slots.default"
|
|
122
|
-
:data-header="
|
|
110
|
+
:data-header="headerStylize"
|
|
123
111
|
class="pxd-drawer--content group flex-1"
|
|
124
112
|
content-class="group-data-[header=true]:pt-5 px-6 pb-5"
|
|
125
113
|
>
|
|
126
114
|
<slot />
|
|
127
115
|
</PScrollable>
|
|
116
|
+
<div v-else class="flex-1" />
|
|
128
117
|
|
|
129
118
|
<footer
|
|
130
119
|
v-if="$slots.footer"
|
|
131
120
|
class="pxd-drawer--footer p-4 gap-2 relative flex shrink-0 items-center justify-between"
|
|
132
|
-
:class="{ 'border-t bg-background-200 dark:bg-background-100':
|
|
121
|
+
:class="{ 'border-t bg-background-200 dark:bg-background-100': footerStylize }"
|
|
133
122
|
>
|
|
134
123
|
<slot name="footer" />
|
|
135
124
|
</footer>
|
|
@@ -139,38 +128,70 @@ watch(() => isVisible.value, (visible) => {
|
|
|
139
128
|
</template>
|
|
140
129
|
|
|
141
130
|
<style>
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
131
|
+
.pxd-drawer {
|
|
132
|
+
&[data-position="left"] {
|
|
133
|
+
left: 0;
|
|
134
|
+
top: 0;
|
|
135
|
+
bottom: 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&[data-position="top"] {
|
|
139
|
+
left: 0;
|
|
140
|
+
top: 0;
|
|
141
|
+
right: 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&[data-position="right"] {
|
|
145
|
+
right: 0;
|
|
146
|
+
top: 0;
|
|
147
|
+
bottom: 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&[data-position="bottom"] {
|
|
151
|
+
left: 0;
|
|
152
|
+
bottom: 0;
|
|
153
|
+
right: 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.pxd-drawer[data-position="left"],
|
|
158
|
+
.pxd-drawer[data-position="right"] {
|
|
159
|
+
width: var(--size, var(--w, 80vw));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.pxd-drawer[data-position="top"],
|
|
163
|
+
.pxd-drawer[data-position="bottom"] {
|
|
164
|
+
height: var(--size, var(--h, 80vw));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.pxd-transition--drawer-right-enter-active,
|
|
168
|
+
.pxd-transition--drawer-right-leave-active,
|
|
169
|
+
.pxd-transition--drawer-left-enter-active,
|
|
170
|
+
.pxd-transition--drawer-left-leave-active,
|
|
171
|
+
.pxd-transition--drawer-top-enter-active,
|
|
172
|
+
.pxd-transition--drawer-top-leave-active,
|
|
173
|
+
.pxd-transition--drawer-bottom-enter-active,
|
|
174
|
+
.pxd-transition--drawer-bottom-leave-active {
|
|
154
175
|
transition: transform var(--default-transition-duration, 0.3s) var(--default-transition-timing-function);
|
|
155
176
|
}
|
|
156
177
|
|
|
157
|
-
.pxd-transition--drawer-
|
|
158
|
-
.pxd-transition--drawer-
|
|
178
|
+
.pxd-transition--drawer-right-leave-to,
|
|
179
|
+
.pxd-transition--drawer-right-enter-from {
|
|
159
180
|
transform: translateX(100%);
|
|
160
181
|
}
|
|
161
182
|
|
|
162
|
-
.pxd-transition--drawer-
|
|
163
|
-
.pxd-transition--drawer-
|
|
183
|
+
.pxd-transition--drawer-left-leave-to,
|
|
184
|
+
.pxd-transition--drawer-left-enter-from {
|
|
164
185
|
transform: translateX(-100%);
|
|
165
186
|
}
|
|
166
187
|
|
|
167
|
-
.pxd-transition--drawer-
|
|
168
|
-
.pxd-transition--drawer-
|
|
188
|
+
.pxd-transition--drawer-top-leave-to,
|
|
189
|
+
.pxd-transition--drawer-top-enter-from {
|
|
169
190
|
transform: translateY(-100%);
|
|
170
191
|
}
|
|
171
192
|
|
|
172
|
-
.pxd-transition--drawer-
|
|
173
|
-
.pxd-transition--drawer-
|
|
193
|
+
.pxd-transition--drawer-bottom-leave-to,
|
|
194
|
+
.pxd-transition--drawer-bottom-enter-from {
|
|
174
195
|
transform: translateY(100%);
|
|
175
196
|
}
|
|
176
197
|
</style>
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import type { BasePosition, ComponentLabel } from '../../types/shared';
|
|
1
|
+
import type { BasePosition, ComponentClass, ComponentLabel } from '../../types/shared';
|
|
2
2
|
interface Props {
|
|
3
|
-
size?: number | string;
|
|
4
3
|
title?: ComponentLabel;
|
|
5
4
|
subtitle?: ComponentLabel;
|
|
5
|
+
size?: number | string;
|
|
6
|
+
pending?: boolean;
|
|
7
|
+
position?: BasePosition;
|
|
6
8
|
modelValue?: boolean;
|
|
7
|
-
headerStyle?: boolean;
|
|
8
|
-
footerStyle?: boolean;
|
|
9
9
|
appendToBody?: boolean;
|
|
10
|
+
headerStylize?: boolean;
|
|
11
|
+
footerStylize?: boolean;
|
|
12
|
+
drawerClass?: ComponentClass;
|
|
10
13
|
closeOnPressEscape?: boolean;
|
|
11
14
|
closeOnClickOverlay?: boolean;
|
|
12
|
-
position?: BasePosition;
|
|
13
15
|
}
|
|
14
16
|
declare var __VLS_14: {}, __VLS_16: {}, __VLS_22: {}, __VLS_24: {};
|
|
15
17
|
type __VLS_Slots = {} & {
|
|
@@ -33,13 +35,12 @@ declare const __VLS_component: import("vue").DefineComponent<Props, void, {}, {}
|
|
|
33
35
|
"onClick-outside"?: (args_0: MouseEvent) => any;
|
|
34
36
|
}>, {
|
|
35
37
|
position: BasePosition;
|
|
36
|
-
size: number | string;
|
|
37
38
|
modelValue: boolean;
|
|
38
39
|
closeOnPressEscape: boolean;
|
|
39
40
|
appendToBody: boolean;
|
|
40
|
-
headerStyle: boolean;
|
|
41
|
-
footerStyle: boolean;
|
|
42
41
|
closeOnClickOverlay: boolean;
|
|
42
|
+
headerStylize: boolean;
|
|
43
|
+
footerStylize: boolean;
|
|
43
44
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
44
45
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
45
46
|
export default _default;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, onBeforeUnmount, onMounted, shallowRef } from "vue";
|
|
3
|
-
import { provideListContext } from "../../contexts/list";
|
|
3
|
+
import { provideListContext, provideListItemIndexContext } from "../../contexts/list";
|
|
4
4
|
import { off, on } from "../../utils/events";
|
|
5
5
|
import { getCssUnitValue } from "../../utils/format";
|
|
6
6
|
import { isServer } from "../../utils/is";
|
|
@@ -18,29 +18,24 @@ const props = defineProps({
|
|
|
18
18
|
const emits = defineEmits(["close", "toggle", "selected"]);
|
|
19
19
|
const ITEM_CLASS = "pxd-list-item";
|
|
20
20
|
const ITEM_SELECTOR = `.${ITEM_CLASS}`;
|
|
21
|
-
const
|
|
21
|
+
const initialIndex = Number.NaN;
|
|
22
|
+
const activeIndex = shallowRef(initialIndex);
|
|
23
|
+
const increaseIndex = shallowRef(0);
|
|
22
24
|
const allItems = shallowRef([]);
|
|
23
25
|
const computedStyle = computed(() => {
|
|
24
26
|
return {
|
|
25
27
|
width: getCssUnitValue(props.width)
|
|
26
28
|
};
|
|
27
29
|
});
|
|
28
|
-
function updateAllItemsIndex() {
|
|
29
|
-
allItems.value.forEach((item, index) => {
|
|
30
|
-
item.dataset.index = String(index);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
30
|
function registerListItem(el) {
|
|
34
31
|
if (!allItems.value.includes(el)) {
|
|
35
32
|
allItems.value.push(el);
|
|
36
|
-
updateAllItemsIndex();
|
|
37
33
|
}
|
|
38
34
|
}
|
|
39
35
|
function unregisterListItem(el) {
|
|
40
36
|
const index = allItems.value.indexOf(el);
|
|
41
|
-
if (index
|
|
37
|
+
if (index >= 0) {
|
|
42
38
|
allItems.value.splice(index, 1);
|
|
43
|
-
updateAllItemsIndex();
|
|
44
39
|
}
|
|
45
40
|
}
|
|
46
41
|
function getItemData(index) {
|
|
@@ -48,9 +43,10 @@ function getItemData(index) {
|
|
|
48
43
|
if (!element) {
|
|
49
44
|
return null;
|
|
50
45
|
}
|
|
46
|
+
const { disabled, type = "default" } = element.dataset;
|
|
51
47
|
return {
|
|
52
|
-
disabled:
|
|
53
|
-
type
|
|
48
|
+
disabled: disabled === "true",
|
|
49
|
+
type
|
|
54
50
|
};
|
|
55
51
|
}
|
|
56
52
|
function getCorrectIndex(dir, index) {
|
|
@@ -70,6 +66,8 @@ function getCorrectIndex(dir, index) {
|
|
|
70
66
|
}
|
|
71
67
|
const PREV_KEYS = ["ArrowUp", "ArrowLeft"];
|
|
72
68
|
const NEXT_KEYS = ["ArrowDown", "ArrowRight"];
|
|
69
|
+
const FUNCTION_KEYS = ["Enter", "Escape", "Tab"];
|
|
70
|
+
const PREVENT_DEFAULT_KEYS = [...FUNCTION_KEYS, ...PREV_KEYS, ...NEXT_KEYS];
|
|
73
71
|
const THROTTLE_INTERVALS = 255;
|
|
74
72
|
const containerKeydownThrottled = throttle((ev) => {
|
|
75
73
|
const count = allItems.value.length;
|
|
@@ -89,10 +87,10 @@ const containerKeydownThrottled = throttle((ev) => {
|
|
|
89
87
|
return;
|
|
90
88
|
}
|
|
91
89
|
if (PREV_KEYS.includes(key)) {
|
|
92
|
-
activeIndex.value = activeIndex.value
|
|
90
|
+
activeIndex.value = Object.is(activeIndex.value, initialIndex) ? count - 1 : getCorrectIndex("prev", activeIndex.value);
|
|
93
91
|
emits("toggle", activeIndex.value);
|
|
94
92
|
} else if (NEXT_KEYS.includes(key)) {
|
|
95
|
-
activeIndex.value = activeIndex.value
|
|
93
|
+
activeIndex.value = Object.is(activeIndex.value, initialIndex) ? 0 : getCorrectIndex("next", activeIndex.value);
|
|
96
94
|
emits("toggle", activeIndex.value);
|
|
97
95
|
}
|
|
98
96
|
if (allItems.value.length <= 0 || activeIndex.value < 0) {
|
|
@@ -103,7 +101,10 @@ const containerKeydownThrottled = throttle((ev) => {
|
|
|
103
101
|
});
|
|
104
102
|
}, THROTTLE_INTERVALS, { edges: ["leading"] });
|
|
105
103
|
function onContainerKeydown(ev) {
|
|
106
|
-
ev.
|
|
104
|
+
if (PREVENT_DEFAULT_KEYS.includes(ev.key)) {
|
|
105
|
+
ev.preventDefault();
|
|
106
|
+
}
|
|
107
|
+
ev.stopPropagation();
|
|
107
108
|
containerKeydownThrottled(ev);
|
|
108
109
|
}
|
|
109
110
|
function onPointerOver(ev) {
|
|
@@ -119,6 +120,7 @@ function onOptionClick(ev, index) {
|
|
|
119
120
|
emits("selected", ev, index);
|
|
120
121
|
emits("close");
|
|
121
122
|
}
|
|
123
|
+
provideListItemIndexContext(increaseIndex);
|
|
122
124
|
provideListContext({
|
|
123
125
|
activeIndex,
|
|
124
126
|
onOptionClick,
|
|
@@ -132,9 +134,6 @@ onMounted(() => {
|
|
|
132
134
|
on(document, "keydown", onContainerKeydown);
|
|
133
135
|
});
|
|
134
136
|
onBeforeUnmount(() => {
|
|
135
|
-
if (isServer) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
137
|
off(document, "keydown", onContainerKeydown);
|
|
139
138
|
allItems.value = [];
|
|
140
139
|
});
|
|
@@ -144,10 +143,9 @@ onBeforeUnmount(() => {
|
|
|
144
143
|
<ul
|
|
145
144
|
role="list"
|
|
146
145
|
tabindex="-1"
|
|
147
|
-
class="pxd-list"
|
|
146
|
+
class="pxd-list max-w-full"
|
|
148
147
|
:style="computedStyle"
|
|
149
148
|
@pointerover="onPointerOver"
|
|
150
|
-
@keydown="onContainerKeydown"
|
|
151
149
|
>
|
|
152
150
|
<PScrollable class="max-h-68" content-class="pr-2">
|
|
153
151
|
<slot>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, onMounted, onUnmounted, shallowRef } from "vue";
|
|
3
|
-
import { useListContext } from "../../contexts/list";
|
|
2
|
+
import { computed, onMounted, onUnmounted, shallowRef, useAttrs } from "vue";
|
|
3
|
+
import { useListContext, useListItemIndexContext } from "../../contexts/list";
|
|
4
4
|
defineOptions({
|
|
5
5
|
name: "PListItem"
|
|
6
6
|
});
|
|
7
7
|
const props = defineProps({
|
|
8
8
|
as: { type: null, required: false, default: "li" },
|
|
9
|
-
type: { type:
|
|
10
|
-
label: { type:
|
|
11
|
-
disabled: { type:
|
|
9
|
+
type: { type: null, required: false, default: "default" },
|
|
10
|
+
label: { type: null, required: false },
|
|
11
|
+
disabled: { type: null, required: false, default: false },
|
|
12
|
+
description: { type: null, required: false }
|
|
12
13
|
});
|
|
13
14
|
const emits = defineEmits(["click"]);
|
|
14
15
|
const {
|
|
@@ -17,76 +18,56 @@ const {
|
|
|
17
18
|
registerListItem,
|
|
18
19
|
unregisterListItem
|
|
19
20
|
} = useListContext();
|
|
21
|
+
const listItemIndex = useListItemIndexContext();
|
|
22
|
+
const attrs = useAttrs();
|
|
20
23
|
const itemRef = shallowRef();
|
|
21
|
-
const currentIndex = shallowRef(
|
|
24
|
+
const currentIndex = shallowRef(listItemIndex.value++);
|
|
25
|
+
const itemTypeMap = {
|
|
26
|
+
error: "text-red-900 data-[selected=true]:bg-red-100",
|
|
27
|
+
warning: "text-amber-900 data-[selected=true]:bg-amber-100",
|
|
28
|
+
default: "text-foreground data-[selected=true]:bg-gray-alpha-100"
|
|
29
|
+
};
|
|
30
|
+
const isSelected = computed(() => activeIndex.value === currentIndex.value);
|
|
22
31
|
const computedClass = computed(() => {
|
|
23
|
-
const classes = [];
|
|
24
|
-
if (props.type
|
|
25
|
-
classes.push(
|
|
26
|
-
}
|
|
27
|
-
if (props.disabled) {
|
|
28
|
-
classes.push("pointer-events-none text-gray-700");
|
|
29
|
-
} else {
|
|
30
|
-
classes.push("cursor-pointer");
|
|
32
|
+
const classes = ["cursor-pointer data-[disabled=true]:pointer-events-none data-[disabled=true]:text-gray-700", attrs.class];
|
|
33
|
+
if (props.type) {
|
|
34
|
+
classes.push(itemTypeMap[props.type]);
|
|
31
35
|
}
|
|
32
36
|
return classes.join(" ");
|
|
33
37
|
});
|
|
34
|
-
function setRef(el) {
|
|
35
|
-
if (!el) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
itemRef.value = el instanceof HTMLElement ? el : el.$el;
|
|
39
|
-
if (registerListItem) {
|
|
40
|
-
registerListItem(itemRef.value);
|
|
41
|
-
}
|
|
42
|
-
updateCurrentIndex();
|
|
43
|
-
}
|
|
44
|
-
function updateCurrentIndex() {
|
|
45
|
-
if (itemRef.value && itemRef.value.dataset.index) {
|
|
46
|
-
currentIndex.value = Number(itemRef.value.dataset.index);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
38
|
function onItemClick(ev) {
|
|
50
39
|
emits("click", ev, currentIndex.value);
|
|
51
40
|
onOptionClick?.(ev, currentIndex.value);
|
|
52
41
|
}
|
|
53
42
|
onMounted(() => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
updateCurrentIndex();
|
|
57
|
-
});
|
|
58
|
-
if (itemRef.value) {
|
|
59
|
-
observer.observe(itemRef.value, {
|
|
60
|
-
attributes: true,
|
|
61
|
-
attributeFilter: ["data-index"]
|
|
62
|
-
});
|
|
43
|
+
if (registerListItem) {
|
|
44
|
+
registerListItem(itemRef.value);
|
|
63
45
|
}
|
|
64
|
-
onUnmounted(() => {
|
|
65
|
-
observer.disconnect();
|
|
66
|
-
});
|
|
67
46
|
});
|
|
68
47
|
onUnmounted(() => {
|
|
69
|
-
if (
|
|
48
|
+
if (unregisterListItem) {
|
|
70
49
|
unregisterListItem(itemRef.value);
|
|
71
50
|
}
|
|
72
51
|
});
|
|
73
52
|
</script>
|
|
74
53
|
|
|
75
54
|
<template>
|
|
76
|
-
<
|
|
55
|
+
<Component
|
|
77
56
|
:is="as"
|
|
78
|
-
|
|
57
|
+
ref="itemRef"
|
|
79
58
|
tabindex="-1"
|
|
80
59
|
role="listitem"
|
|
60
|
+
:data-type="type"
|
|
81
61
|
:data-index="currentIndex"
|
|
82
62
|
:data-disabled="disabled"
|
|
83
|
-
:data-selected="
|
|
84
|
-
class="pxd-list-item h-10 px-2 text-sm flex w-full items-center rounded-md outline-none
|
|
63
|
+
:data-selected="isSelected"
|
|
64
|
+
class="pxd-list-item h-10 gap-1 px-2 text-sm flex w-full items-center rounded-md outline-none motion-safe:transition-colors"
|
|
85
65
|
:class="computedClass"
|
|
86
66
|
@click="onItemClick"
|
|
87
67
|
>
|
|
88
68
|
<slot>
|
|
89
|
-
{{ label }}
|
|
69
|
+
<span class="gap-2 flex items-center">{{ label }}</span>
|
|
70
|
+
<span v-if="description" class="text-sm text-foreground-secondary">{{ description }}</span>
|
|
90
71
|
</slot>
|
|
91
72
|
</component>
|
|
92
73
|
</template>
|