cynx-lib 1.3.66 → 1.3.68
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 +1 -1
- package/ui/components/DatePicker.jsx +163 -23
- package/ui/components/Drawer.jsx +208 -0
- package/ui/index.cjs +3 -0
- package/ui/index.js +2 -0
- package/vue/components/Badge.vue +8 -0
- package/vue/components/DatePicker.vue +978 -0
- package/vue/components/Drawer.vue +243 -0
- package/vue/components/Select.vue +10 -6
- package/vue/index.js +6 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch, onUnmounted, computed } from "vue";
|
|
3
|
+
import { X } from "lucide-vue-next";
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(
|
|
6
|
+
defineProps<{
|
|
7
|
+
modelValue?: boolean;
|
|
8
|
+
open?: boolean;
|
|
9
|
+
title?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
width?: number | string;
|
|
12
|
+
maxWidth?: number | string;
|
|
13
|
+
side?: "right" | "left";
|
|
14
|
+
showClose?: boolean;
|
|
15
|
+
bodyStyle?: Record<string, any>;
|
|
16
|
+
style?: Record<string, any>;
|
|
17
|
+
}>(),
|
|
18
|
+
{
|
|
19
|
+
modelValue: false,
|
|
20
|
+
open: false,
|
|
21
|
+
title: "",
|
|
22
|
+
description: "",
|
|
23
|
+
width: 560,
|
|
24
|
+
maxWidth: "100vw",
|
|
25
|
+
side: "right",
|
|
26
|
+
showClose: true,
|
|
27
|
+
bodyStyle: () => ({}),
|
|
28
|
+
style: () => ({}),
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits<{
|
|
33
|
+
(e: "update:modelValue", value: boolean): void;
|
|
34
|
+
(e: "update:open", value: boolean): void;
|
|
35
|
+
(e: "close"): void;
|
|
36
|
+
}>();
|
|
37
|
+
|
|
38
|
+
const isOpen = computed(() => props.modelValue || props.open);
|
|
39
|
+
const closing = ref(false);
|
|
40
|
+
|
|
41
|
+
const STYLES = `
|
|
42
|
+
@keyframes cynxDrawerFadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
43
|
+
@keyframes cynxDrawerFadeOut { from { opacity: 1; } to { opacity: 0; } }
|
|
44
|
+
@keyframes cynxDrawerSlideInRight { from { transform: translateX(100%); } to { transform: translateX(0); } }
|
|
45
|
+
@keyframes cynxDrawerSlideOutRight { from { transform: translateX(0); } to { transform: translateX(100%); } }
|
|
46
|
+
@keyframes cynxDrawerSlideInLeft { from { transform: translateX(-100%); } to { transform: translateX(0); } }
|
|
47
|
+
@keyframes cynxDrawerSlideOutLeft { from { transform: translateX(0); } to { transform: translateX(-100%); } }
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
let _id = "cynx-drawer-styles";
|
|
51
|
+
function ensureStyles() {
|
|
52
|
+
if (typeof document === "undefined") return;
|
|
53
|
+
if (document.getElementById(_id)) return;
|
|
54
|
+
const tag = document.createElement("style");
|
|
55
|
+
tag.id = _id;
|
|
56
|
+
tag.textContent = STYLES;
|
|
57
|
+
document.head.appendChild(tag);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (typeof document !== "undefined") ensureStyles();
|
|
61
|
+
|
|
62
|
+
function close() {
|
|
63
|
+
if (closing.value) return;
|
|
64
|
+
closing.value = true;
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
closing.value = false;
|
|
67
|
+
emit("update:modelValue", false);
|
|
68
|
+
emit("update:open", false);
|
|
69
|
+
emit("close");
|
|
70
|
+
}, 260);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
74
|
+
if (e.key === "Escape" && isOpen.value) {
|
|
75
|
+
close();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
watch(
|
|
80
|
+
isOpen,
|
|
81
|
+
(val) => {
|
|
82
|
+
if (typeof document === "undefined") return;
|
|
83
|
+
if (val) {
|
|
84
|
+
document.body.style.overflow = "hidden";
|
|
85
|
+
window.addEventListener("keydown", handleKeydown);
|
|
86
|
+
} else {
|
|
87
|
+
document.body.style.overflow = "";
|
|
88
|
+
window.removeEventListener("keydown", handleKeydown);
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{ immediate: true }
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
onUnmounted(() => {
|
|
95
|
+
if (typeof document !== "undefined") {
|
|
96
|
+
document.body.style.overflow = "";
|
|
97
|
+
window.removeEventListener("keydown", handleKeydown);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const resolvedWidth = computed(() => {
|
|
102
|
+
if (typeof props.width === "number") return `${props.width}px`;
|
|
103
|
+
return props.width;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const slideInAnim = computed(() =>
|
|
107
|
+
props.side === "left" ? "cynxDrawerSlideInLeft" : "cynxDrawerSlideInRight"
|
|
108
|
+
);
|
|
109
|
+
const slideOutAnim = computed(() =>
|
|
110
|
+
props.side === "left" ? "cynxDrawerSlideOutLeft" : "cynxDrawerSlideOutRight"
|
|
111
|
+
);
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<template>
|
|
115
|
+
<Teleport to="body">
|
|
116
|
+
<div
|
|
117
|
+
v-if="isOpen || closing"
|
|
118
|
+
class="cynx-drawer-backdrop"
|
|
119
|
+
:style="{
|
|
120
|
+
position: 'fixed',
|
|
121
|
+
inset: 0,
|
|
122
|
+
background: 'rgba(20, 22, 41, .45)',
|
|
123
|
+
zIndex: 8500,
|
|
124
|
+
display: 'flex',
|
|
125
|
+
justifyContent: side === 'left' ? 'flex-start' : 'flex-end',
|
|
126
|
+
animation: `${closing ? 'cynxDrawerFadeOut' : 'cynxDrawerFadeIn'} .26s ease forwards`,
|
|
127
|
+
}"
|
|
128
|
+
@mousedown.self="close"
|
|
129
|
+
>
|
|
130
|
+
<div
|
|
131
|
+
class="cynx-drawer-panel"
|
|
132
|
+
:style="{
|
|
133
|
+
background: 'var(--surface, #ffffff)',
|
|
134
|
+
borderLeft: side === 'right' ? '1px solid var(--border, var(--bd, #e2e8f0))' : 'none',
|
|
135
|
+
borderRight: side === 'left' ? '1px solid var(--border, var(--bd, #e2e8f0))' : 'none',
|
|
136
|
+
width: resolvedWidth,
|
|
137
|
+
maxWidth: '100vw',
|
|
138
|
+
height: '100%',
|
|
139
|
+
boxShadow: 'var(--shadow-lg, 0 20px 60px rgba(0, 0, 0, .25))',
|
|
140
|
+
display: 'flex',
|
|
141
|
+
flexDirection: 'column',
|
|
142
|
+
overflow: 'hidden',
|
|
143
|
+
animation: `${closing ? slideOutAnim : slideInAnim} .26s cubic-bezier(.16, 1, .3, 1) forwards`,
|
|
144
|
+
...style,
|
|
145
|
+
}"
|
|
146
|
+
@mousedown.stop
|
|
147
|
+
>
|
|
148
|
+
<!-- Header -->
|
|
149
|
+
<div
|
|
150
|
+
class="cynx-drawer-hdr"
|
|
151
|
+
:style="{
|
|
152
|
+
display: 'flex',
|
|
153
|
+
alignItems: 'center',
|
|
154
|
+
justifyContent: 'space-between',
|
|
155
|
+
padding: '16px 20px',
|
|
156
|
+
borderBottom: '1px solid var(--border-light, #ebebf0)',
|
|
157
|
+
flexShrink: 0,
|
|
158
|
+
}"
|
|
159
|
+
>
|
|
160
|
+
<slot name="header">
|
|
161
|
+
<div style="display: flex; flex-direction: column; gap: 2px;">
|
|
162
|
+
<span
|
|
163
|
+
class="cynx-drawer-title"
|
|
164
|
+
:style="{
|
|
165
|
+
fontSize: '1rem',
|
|
166
|
+
fontWeight: 700,
|
|
167
|
+
letterSpacing: '-.01em',
|
|
168
|
+
color: 'var(--t, var(--primary-text, #0f111c))',
|
|
169
|
+
}"
|
|
170
|
+
>
|
|
171
|
+
{{ title }}
|
|
172
|
+
</span>
|
|
173
|
+
<span
|
|
174
|
+
v-if="description"
|
|
175
|
+
class="cynx-drawer-desc"
|
|
176
|
+
:style="{
|
|
177
|
+
fontSize: '.75rem',
|
|
178
|
+
color: 'var(--muted, #797b8d)',
|
|
179
|
+
}"
|
|
180
|
+
>
|
|
181
|
+
{{ description }}
|
|
182
|
+
</span>
|
|
183
|
+
</div>
|
|
184
|
+
</slot>
|
|
185
|
+
|
|
186
|
+
<button
|
|
187
|
+
v-if="showClose"
|
|
188
|
+
type="button"
|
|
189
|
+
class="cynx-drawer-close"
|
|
190
|
+
:style="{
|
|
191
|
+
background: 'none',
|
|
192
|
+
border: 'none',
|
|
193
|
+
cursor: 'pointer',
|
|
194
|
+
padding: '6px',
|
|
195
|
+
borderRadius: '6px',
|
|
196
|
+
color: 'var(--muted, #797b8d)',
|
|
197
|
+
display: 'flex',
|
|
198
|
+
alignItems: 'center',
|
|
199
|
+
justifyContent: 'center',
|
|
200
|
+
transition: 'all .14s',
|
|
201
|
+
}"
|
|
202
|
+
@click="close"
|
|
203
|
+
>
|
|
204
|
+
<X :size="18" />
|
|
205
|
+
</button>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<!-- Body -->
|
|
209
|
+
<div
|
|
210
|
+
class="cynx-drawer-body custom-scrollbar"
|
|
211
|
+
:style="{
|
|
212
|
+
padding: '20px',
|
|
213
|
+
overflowX: 'hidden',
|
|
214
|
+
overflowY: 'auto',
|
|
215
|
+
flex: '1 1 auto',
|
|
216
|
+
minHeight: 0,
|
|
217
|
+
color: 'var(--t, var(--primary-text, #0f111c))',
|
|
218
|
+
...bodyStyle,
|
|
219
|
+
}"
|
|
220
|
+
>
|
|
221
|
+
<slot />
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
<!-- Footer -->
|
|
225
|
+
<div
|
|
226
|
+
v-if="$slots.footer"
|
|
227
|
+
class="cynx-drawer-footer"
|
|
228
|
+
:style="{
|
|
229
|
+
display: 'flex',
|
|
230
|
+
justifyContent: 'flex-end',
|
|
231
|
+
gap: '8px',
|
|
232
|
+
padding: '14px 20px',
|
|
233
|
+
borderTop: '1px solid var(--border-light, #ebebf0)',
|
|
234
|
+
background: 'var(--grey-1, #f5f5f8)',
|
|
235
|
+
flexShrink: 0,
|
|
236
|
+
}"
|
|
237
|
+
>
|
|
238
|
+
<slot name="footer" />
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
</Teleport>
|
|
243
|
+
</template>
|
|
@@ -64,6 +64,7 @@ const props = withDefaults(
|
|
|
64
64
|
placeholder?: string;
|
|
65
65
|
disabled?: boolean;
|
|
66
66
|
multi?: boolean;
|
|
67
|
+
multiple?: boolean;
|
|
67
68
|
searchable?: boolean;
|
|
68
69
|
clearable?: boolean;
|
|
69
70
|
size?: "xs" | "sm" | "md" | "lg";
|
|
@@ -82,6 +83,7 @@ const props = withDefaults(
|
|
|
82
83
|
placeholder: "Select...",
|
|
83
84
|
disabled: false,
|
|
84
85
|
multi: false,
|
|
86
|
+
multiple: false,
|
|
85
87
|
searchable: false,
|
|
86
88
|
clearable: false,
|
|
87
89
|
size: "md",
|
|
@@ -118,9 +120,11 @@ const currentVal = computed(() => {
|
|
|
118
120
|
return props.modelValue !== undefined ? props.modelValue : props.value;
|
|
119
121
|
});
|
|
120
122
|
|
|
123
|
+
const isMulti = computed(() => Boolean(props.multi || props.multiple));
|
|
124
|
+
|
|
121
125
|
const selectedValues = computed<any[]>(() => {
|
|
122
126
|
const v = currentVal.value;
|
|
123
|
-
if (
|
|
127
|
+
if (isMulti.value) {
|
|
124
128
|
return Array.isArray(v) ? v : [];
|
|
125
129
|
}
|
|
126
130
|
return v !== undefined && v !== null && v !== "" ? [v] : [];
|
|
@@ -133,7 +137,7 @@ function getLabel(optVal: any) {
|
|
|
133
137
|
|
|
134
138
|
function isSelected(optVal: any) {
|
|
135
139
|
const v = currentVal.value;
|
|
136
|
-
return
|
|
140
|
+
return isMulti.value ? (Array.isArray(v) && v.includes(optVal)) : v === optVal;
|
|
137
141
|
}
|
|
138
142
|
|
|
139
143
|
const radiusVal = computed(() => {
|
|
@@ -279,7 +283,7 @@ function handleOpen() {
|
|
|
279
283
|
}
|
|
280
284
|
|
|
281
285
|
function toggleOption(optVal: any) {
|
|
282
|
-
if (
|
|
286
|
+
if (isMulti.value) {
|
|
283
287
|
const arr = Array.isArray(currentVal.value) ? currentVal.value : [];
|
|
284
288
|
const next = arr.includes(optVal)
|
|
285
289
|
? arr.filter((v: any) => v !== optVal)
|
|
@@ -304,7 +308,7 @@ function removeTag(e: MouseEvent, valToRemove: any) {
|
|
|
304
308
|
|
|
305
309
|
function handleClear(e: MouseEvent) {
|
|
306
310
|
e.stopPropagation();
|
|
307
|
-
const next =
|
|
311
|
+
const next = isMulti.value ? [] : "";
|
|
308
312
|
emit("update:modelValue", next);
|
|
309
313
|
emit("change", next);
|
|
310
314
|
emit("clear");
|
|
@@ -385,10 +389,10 @@ function handleInputKeyDown(e: KeyboardEvent) {
|
|
|
385
389
|
<slot
|
|
386
390
|
v-if="slots.label && selectedValues.length > 0"
|
|
387
391
|
name="label"
|
|
388
|
-
:value="
|
|
392
|
+
:value="isMulti ? selectedValues : selectedValues[0]"
|
|
389
393
|
/>
|
|
390
394
|
|
|
391
|
-
<template v-else-if="
|
|
395
|
+
<template v-else-if="isMulti && selectedValues.length > 0">
|
|
392
396
|
<span
|
|
393
397
|
v-if="showCount"
|
|
394
398
|
style="
|
package/vue/index.js
CHANGED
|
@@ -11,7 +11,9 @@ import Table from "./components/Table.vue";
|
|
|
11
11
|
import Pagination from "./components/Pagination.vue";
|
|
12
12
|
import Skeleton from "./components/Skeleton.vue";
|
|
13
13
|
import Modal from "./components/Modal.vue";
|
|
14
|
+
import Drawer from "./components/Drawer.vue";
|
|
14
15
|
import Toggle from "./components/Toggle.vue";
|
|
16
|
+
import DatePicker from "./components/DatePicker.vue";
|
|
15
17
|
import { XTable, XThead, XTbody, XTr, XTh, XTd } from "./components/XTable.vue";
|
|
16
18
|
import { useAutoSkeletonRows } from "./composables/useAutoSkeletonRows";
|
|
17
19
|
|
|
@@ -28,7 +30,9 @@ export {
|
|
|
28
30
|
Pagination,
|
|
29
31
|
Skeleton,
|
|
30
32
|
Modal,
|
|
33
|
+
Drawer,
|
|
31
34
|
Toggle,
|
|
35
|
+
DatePicker,
|
|
32
36
|
XTable,
|
|
33
37
|
XThead,
|
|
34
38
|
XTbody,
|
|
@@ -51,7 +55,9 @@ export default {
|
|
|
51
55
|
Pagination,
|
|
52
56
|
Skeleton,
|
|
53
57
|
Modal,
|
|
58
|
+
Drawer,
|
|
54
59
|
Toggle,
|
|
60
|
+
DatePicker,
|
|
55
61
|
XTable,
|
|
56
62
|
XThead,
|
|
57
63
|
XTbody,
|