vlite3 0.0.9 → 0.1.1
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/README.md +126 -24
- package/components/Alert.vue.js +11 -8
- package/components/Avatar.vue.js +11 -11
- package/components/AvatarUploader/AvatarUploader.vue.d.ts +1 -1
- package/components/AvatarUploader/AvatarUploader.vue.js +71 -71
- package/components/CheckBox.vue.js +3 -3
- package/components/ChoiceBox/ChoiceBox.vue.js +16 -16
- package/components/DataTable/DataTableRow.vue.js +2 -2
- package/components/Dropdown/DropdownMenu.vue.js +19 -19
- package/components/FilePicker/FilePicker.vue.js +45 -42
- package/components/FileTree/FileTreeNode.vue.js +1 -1
- package/components/Form/Form.vue.d.ts +1 -1
- package/components/Form/FormField.vue.js +45 -50
- package/components/Modal.vue.d.ts +5 -0
- package/components/Modal.vue.js +57 -48
- package/components/SidePanel.vue.d.ts +2 -0
- package/components/SidePanel.vue.js +2 -2
- package/components/SidePanel.vue2.js +15 -14
- package/components/ToastNotification.vue.js +2 -2
- package/components/ToastNotification.vue2.js +24 -24
- package/composables/useNotifications.d.ts +27 -10
- package/composables/useNotifications.js +82 -78
- package/index.js +51 -45
- package/package.json +1 -1
- package/style.css +316 -320
package/README.md
CHANGED
|
@@ -63,30 +63,25 @@ vlite3 uses a semantic theming system inspired by **shadcn/ui** and compatible w
|
|
|
63
63
|
|
|
64
64
|
You can customize these colors in your CSS by overriding the variables in `:root` or `.dark` classes (if you are using a class-based dark mode switcher).
|
|
65
65
|
|
|
66
|
-
| Variable | Class Name | Description
|
|
67
|
-
| :------------------------- | :---------------------------- |
|
|
68
|
-
| `--background` | `bg-background` | Default page background
|
|
69
|
-
| `--foreground` | `text-foreground` | Default text color
|
|
70
|
-
| `--card` | `bg-card` | Card background
|
|
71
|
-
| `--
|
|
72
|
-
| `--
|
|
73
|
-
| `--
|
|
74
|
-
| `--
|
|
75
|
-
| `--
|
|
76
|
-
| `--
|
|
77
|
-
| `--
|
|
78
|
-
| `--
|
|
79
|
-
| `--
|
|
80
|
-
| `--
|
|
81
|
-
| `--
|
|
82
|
-
| `--
|
|
83
|
-
| `--
|
|
84
|
-
| `--
|
|
85
|
-
| `--destructive-foreground` | `text-destructive-foreground` | Destructive text color | Text color on destructive backgrounds. |
|
|
86
|
-
| `--border` | `border` | Default border color | Borders for inputs, cards, and dividers. |
|
|
87
|
-
| `--input` | `border-input` | Input border color | Borders specifically for form inputs. |
|
|
88
|
-
| `--ring` | `ring-ring` | Focus ring color | Outline color for focused elements. |
|
|
89
|
-
| `--radius` | `rounded-radius` | Border radius | Global border radius for components. |
|
|
66
|
+
| Variable | Class Name | Description | Recommended Usage |
|
|
67
|
+
| :------------------------- | :---------------------------- | :---------------------- | :-------------------------------------------------------------------------- |
|
|
68
|
+
| `--background` | `bg-background` | Default page background | The main background color of your app. |
|
|
69
|
+
| `--foreground` | `text-foreground` | Default text color | The primary text color for content. |
|
|
70
|
+
| `--card` | `bg-card` | Card background | Little Gray Background for cards, containers, surfece, panels, and dialogs. |
|
|
71
|
+
| `--primary` | `bg-primary` | Primary brand color | Used for main actions (buttons, active states). |
|
|
72
|
+
| `--primary-foreground` | `text-primary-foreground` | Primary text color | Text color for content on top of primary background. |
|
|
73
|
+
| `--secondary` | `bg-secondary` | Secondary background | Used for secondary actions or muted sections. |
|
|
74
|
+
| `--secondary-foreground` | `text-secondary-foreground` | Secondary text color | Text color for content on top of secondary background. |
|
|
75
|
+
| `--muted` | `bg-muted` | Muted background | Subtle backgrounds (e.g., table headers, disabled states). |
|
|
76
|
+
| `--muted-foreground` | `text-muted-foreground` | Muted text color | Secondary text, hints, placeholders. |
|
|
77
|
+
| `--accent` | `bg-accent` | Accent background | Used for hover states, selection highlights. |
|
|
78
|
+
| `--accent-foreground` | `text-accent-foreground` | Accent text color | Text color on accent backgrounds. |
|
|
79
|
+
| `--destructive` | `bg-destructive` | Destructive color | Used for error states and destructive actions. |
|
|
80
|
+
| `--destructive-foreground` | `text-destructive-foreground` | Destructive text color | Text color on destructive backgrounds. |
|
|
81
|
+
| `--border` | `border` | Default border color | Borders for inputs, cards, and dividers. |
|
|
82
|
+
| `--input` | `border-input` | Input border color | Borders specifically for form inputs. |
|
|
83
|
+
| `--ring` | `ring-ring` | Focus ring color | Outline color for focused elements. |
|
|
84
|
+
| `--radius` | `rounded` | Border radius | Global border radius for components. |
|
|
90
85
|
|
|
91
86
|
### Extended Color Variants
|
|
92
87
|
|
|
@@ -197,3 +192,110 @@ To customize the theme, simply override the CSS variables in your main CSS file:
|
|
|
197
192
|
- **ToastNotification**
|
|
198
193
|
- **Tooltip**
|
|
199
194
|
- **Dropdown**
|
|
195
|
+
|
|
196
|
+
## Global Configuration (Registry System)
|
|
197
|
+
|
|
198
|
+
vlite3 features a plugin-based architecture that allows you to register global services. This is particularly useful for dependency injection, such as defining how file uploads should be handled across all `Form` components in your app.
|
|
199
|
+
|
|
200
|
+
### Setting up the Plugin
|
|
201
|
+
|
|
202
|
+
In your `main.ts` or `main.js`, import `createVLite` and register your services:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { createApp } from 'vue'
|
|
206
|
+
import App from './App.vue'
|
|
207
|
+
import { createVLite } from 'vlite3'
|
|
208
|
+
|
|
209
|
+
const app = createApp(App)
|
|
210
|
+
|
|
211
|
+
// Initialize VLite with custom configuration
|
|
212
|
+
const vlite = createVLite({
|
|
213
|
+
services: {
|
|
214
|
+
/**
|
|
215
|
+
* Global File Upload Handler
|
|
216
|
+
*
|
|
217
|
+
* This function will be called automatically by:
|
|
218
|
+
* - useFileUpload() composable
|
|
219
|
+
* - Form components (when using 'file', 'fileUploader', or 'avatarUpload' types)
|
|
220
|
+
*
|
|
221
|
+
* @param file - The File object to upload
|
|
222
|
+
* @param folderId - (Optional) Folder ID passed from component props
|
|
223
|
+
* @returns Promise<string> - The public URL of the uploaded file
|
|
224
|
+
*/
|
|
225
|
+
upload: async (file, folderId) => {
|
|
226
|
+
// Example: Upload to your own backend
|
|
227
|
+
const formData = new FormData()
|
|
228
|
+
formData.append('file', file)
|
|
229
|
+
if (folderId) formData.append('folder_id', folderId)
|
|
230
|
+
|
|
231
|
+
// Replace with your actual API call (e.g., Axios, Fetch)
|
|
232
|
+
const response = await fetch(
|
|
233
|
+
'[https://api.yourdomain.com/v1/upload](https://api.yourdomain.com/v1/upload)',
|
|
234
|
+
{
|
|
235
|
+
method: 'POST',
|
|
236
|
+
body: formData,
|
|
237
|
+
headers: {
|
|
238
|
+
Authorization: 'Bearer ...',
|
|
239
|
+
},
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
if (!response.ok) throw new Error('Upload failed')
|
|
244
|
+
|
|
245
|
+
const data = await response.json()
|
|
246
|
+
return data.url // MUST return the file URL string
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
app.use(vlite)
|
|
252
|
+
app.mount('#app')
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### How it works
|
|
256
|
+
|
|
257
|
+
Once registered, you don't need to pass upload handlers to individual components.
|
|
258
|
+
|
|
259
|
+
1. **Automatic Injection**: The `Form` component detects input types like `file`, `avatarUpload`, or `fileUploader`.
|
|
260
|
+
2. **Parallel Processing**: When the form is submitted, it automatically uploads all files in **parallel** using your registered `upload` service.
|
|
261
|
+
3. **URL Replacement**: The File objects in your form data are replaced with the returned URLs before the final `onSubmit` event is triggered.
|
|
262
|
+
|
|
263
|
+
## 4. Usage
|
|
264
|
+
|
|
265
|
+
Import components directly in your Vue files:
|
|
266
|
+
|
|
267
|
+
```vue
|
|
268
|
+
<script setup>
|
|
269
|
+
import { Button, Input, Form } from 'vlite3'
|
|
270
|
+
|
|
271
|
+
// The form will automatically use the global upload service defined in main.ts
|
|
272
|
+
const schema = [
|
|
273
|
+
{
|
|
274
|
+
name: 'avatar',
|
|
275
|
+
label: 'Profile Picture',
|
|
276
|
+
type: 'avatarUpload',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: 'documents',
|
|
280
|
+
label: 'Attachments',
|
|
281
|
+
type: 'fileUploader',
|
|
282
|
+
props: { multiple: true },
|
|
283
|
+
},
|
|
284
|
+
]
|
|
285
|
+
|
|
286
|
+
const handleSubmit = (payload) => {
|
|
287
|
+
// payload.values.avatar will be a URL string (e.g., "https://api...")
|
|
288
|
+
// payload.values.documents will be an array of URL strings
|
|
289
|
+
console.log(payload.values)
|
|
290
|
+
}
|
|
291
|
+
</script>
|
|
292
|
+
|
|
293
|
+
<template>
|
|
294
|
+
<div class="p-4 space-y-4">
|
|
295
|
+
<Button>Click Me</Button>
|
|
296
|
+
<Input placeholder="Type here..." />
|
|
297
|
+
|
|
298
|
+
<Form :schema="schema" @onSubmit="handleSubmit" />
|
|
299
|
+
</div>
|
|
300
|
+
</template>
|
|
301
|
+
```
|
package/components/Alert.vue.js
CHANGED
|
@@ -19,15 +19,15 @@ const j = ["role"], E = {
|
|
|
19
19
|
const t = e, p = f, c = V(!0), y = () => {
|
|
20
20
|
c.value = !1, p("close");
|
|
21
21
|
}, b = a(() => ({
|
|
22
|
-
primary: "bg-primary-light text-primary border-primary/
|
|
23
|
-
success: "bg-success-light text-success-dark border-success/
|
|
22
|
+
primary: "bg-primary-light text-primary border-primary/15",
|
|
23
|
+
success: "bg-success-light text-success-dark border-success/25",
|
|
24
24
|
warning: "bg-warning-light text-warning-dark border-warning/20",
|
|
25
|
-
danger: "bg-danger-light text-danger-dark border-danger/
|
|
25
|
+
danger: "bg-danger-light text-danger-dark border-danger/15"
|
|
26
26
|
})[t.variant]), k = a(() => ({
|
|
27
|
-
primary: "text-primary",
|
|
28
|
-
success: "text-success-dark",
|
|
29
|
-
warning: "text-warning-dark",
|
|
30
|
-
danger: "text-danger-dark"
|
|
27
|
+
primary: "text-primary!",
|
|
28
|
+
success: "text-success-dark!",
|
|
29
|
+
warning: "text-warning-dark!",
|
|
30
|
+
danger: "text-danger-dark!"
|
|
31
31
|
})[t.variant]), l = a(() => !t.description && !$().default), x = a(() => [
|
|
32
32
|
"relative w-full rounded-lg border px-4 [&>svg]:absolute [&>svg]:left-4 [&>svg]:text-foreground",
|
|
33
33
|
l.value ? "py-3" : "pt-4 pb-2",
|
|
@@ -35,7 +35,10 @@ const j = ["role"], E = {
|
|
|
35
35
|
l.value ? "[&>svg]:top-1/2 [&>svg]:-translate-y-1/2" : "[&>svg]:top-4 top-4 [&>svg+div]:translate-y-[-3px]",
|
|
36
36
|
b.value,
|
|
37
37
|
t.class
|
|
38
|
-
].join(" ")), h = a(() => [
|
|
38
|
+
].join(" ")), h = a(() => [
|
|
39
|
+
"font-medium leading-none tracking-tight text-inherit!",
|
|
40
|
+
l.value ? "" : "mb-1"
|
|
41
|
+
].join(" ")), w = a(() => t.role ? t.role : ["danger", "warning"].includes(t.variant) ? "alert" : "status");
|
|
39
42
|
return (s, u) => c.value ? (n(), i("div", {
|
|
40
43
|
key: 0,
|
|
41
44
|
class: r(x.value),
|
package/components/Avatar.vue.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent as k, ref as c, watch as w, computed as a, openBlock as t, createElementBlock as r, normalizeClass as d, renderSlot as
|
|
1
|
+
import { defineComponent as k, ref as c, watch as w, computed as a, openBlock as t, createElementBlock as r, normalizeClass as d, renderSlot as b, toDisplayString as g, createBlock as C } from "vue";
|
|
2
2
|
import _ from "./Icon.vue.js";
|
|
3
3
|
const y = ["src", "alt"], z = { key: 0 }, A = /* @__PURE__ */ k({
|
|
4
4
|
__name: "Avatar",
|
|
@@ -10,18 +10,18 @@ const y = ["src", "alt"], z = { key: 0 }, A = /* @__PURE__ */ k({
|
|
|
10
10
|
rounded: { default: "full" },
|
|
11
11
|
class: { default: "" }
|
|
12
12
|
},
|
|
13
|
-
setup(
|
|
14
|
-
const e =
|
|
13
|
+
setup(o) {
|
|
14
|
+
const e = o, s = c(!1), n = c(!1);
|
|
15
15
|
w(
|
|
16
16
|
() => e.src,
|
|
17
17
|
() => {
|
|
18
|
-
s.value = !1,
|
|
18
|
+
s.value = !1, n.value = !1;
|
|
19
19
|
}
|
|
20
20
|
);
|
|
21
21
|
const f = () => {
|
|
22
|
-
s.value = !0,
|
|
22
|
+
s.value = !0, n.value = !1;
|
|
23
23
|
}, i = () => {
|
|
24
|
-
|
|
24
|
+
n.value = !0, s.value = !1;
|
|
25
25
|
}, m = a(() => e.src && !s.value), u = a(() => {
|
|
26
26
|
if (e.fallback) return e.fallback;
|
|
27
27
|
if (!e.alt) return "";
|
|
@@ -43,7 +43,7 @@ const y = ["src", "alt"], z = { key: 0 }, A = /* @__PURE__ */ k({
|
|
|
43
43
|
"2xl": "rounded-2xl",
|
|
44
44
|
full: "rounded-full"
|
|
45
45
|
}, v = a(() => [
|
|
46
|
-
"relative flex shrink-0 overflow-hidden bg-muted",
|
|
46
|
+
"relative flex shrink-0 overflow-hidden bg-muted border border-border/50",
|
|
47
47
|
x[e.size],
|
|
48
48
|
h[e.rounded],
|
|
49
49
|
e.class
|
|
@@ -53,8 +53,8 @@ const y = ["src", "alt"], z = { key: 0 }, A = /* @__PURE__ */ k({
|
|
|
53
53
|
}, [
|
|
54
54
|
m.value ? (t(), r("img", {
|
|
55
55
|
key: 0,
|
|
56
|
-
src:
|
|
57
|
-
alt:
|
|
56
|
+
src: o.src,
|
|
57
|
+
alt: o.alt,
|
|
58
58
|
class: "aspect-square h-full w-full object-cover",
|
|
59
59
|
onError: f,
|
|
60
60
|
onLoad: i
|
|
@@ -62,8 +62,8 @@ const y = ["src", "alt"], z = { key: 0 }, A = /* @__PURE__ */ k({
|
|
|
62
62
|
key: 1,
|
|
63
63
|
class: d(p.value)
|
|
64
64
|
}, [
|
|
65
|
-
|
|
66
|
-
u.value ? (t(), r("span", z,
|
|
65
|
+
b(l.$slots, "fallback", {}, () => [
|
|
66
|
+
u.value ? (t(), r("span", z, g(u.value), 1)) : (t(), C(_, {
|
|
67
67
|
key: 1,
|
|
68
68
|
icon: "lucide:user",
|
|
69
69
|
class: "h-1/2 w-1/2"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { defineComponent as
|
|
1
|
+
import { defineComponent as x, ref as w, computed as z, openBlock as n, createElementBlock as o, createElementVNode as b, normalizeClass as l, createVNode as d, withCtx as C, createCommentVNode as f, withModifiers as A } from "vue";
|
|
2
2
|
import u from "../Icon.vue.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
const $ = ["onClick"], I = /* @__PURE__ */
|
|
3
|
+
import B from "../FilePicker/FilePicker.vue.js";
|
|
4
|
+
import N from "../Avatar.vue.js";
|
|
5
|
+
const E = { class: "inline-block" }, $ = ["onClick"], I = /* @__PURE__ */ x({
|
|
6
|
+
name: "AvatarUploader",
|
|
6
7
|
__name: "AvatarUploader",
|
|
7
8
|
props: {
|
|
8
9
|
modelValue: { default: null },
|
|
@@ -17,81 +18,80 @@ const $ = ["onClick"], I = /* @__PURE__ */ w({
|
|
|
17
18
|
className: {}
|
|
18
19
|
},
|
|
19
20
|
emits: ["update:modelValue", "change", "error"],
|
|
20
|
-
setup(e, { emit:
|
|
21
|
-
const
|
|
21
|
+
setup(e, { emit: g }) {
|
|
22
|
+
const v = e, t = g, i = w(null), s = z(() => i.value || v.modelValue), h = (a) => {
|
|
22
23
|
if (!a || Array.isArray(a)) {
|
|
23
|
-
Array.isArray(a) && a.length === 0 &&
|
|
24
|
+
Array.isArray(a) && a.length === 0 && c();
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
26
27
|
a.base64 && (i.value = a.base64, t("update:modelValue", a.base64)), t("change", a);
|
|
27
28
|
}, y = (a) => {
|
|
28
29
|
t("error", a);
|
|
29
|
-
},
|
|
30
|
+
}, c = () => {
|
|
30
31
|
i.value = null, t("update:modelValue", null), t("change", null);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
].join(" "));
|
|
36
|
-
return (a, b) => (n(), r("div", {
|
|
37
|
-
class: l(k.value)
|
|
38
|
-
}, [
|
|
39
|
-
o(C(j), {
|
|
40
|
-
disabled: !e.editable || e.disabled || e.loading,
|
|
41
|
-
"return-format": "base64",
|
|
42
|
-
"file-types": ["image/jpeg", "image/png", "image/webp", "image/gif"],
|
|
43
|
-
"max-size": e.maxSize,
|
|
44
|
-
class: "w-auto h-auto block",
|
|
45
|
-
onChange: b[0] || (b[0] = (d) => h(d)),
|
|
46
|
-
onError: y
|
|
47
|
-
}, {
|
|
48
|
-
trigger: A(({ trigger: d, isLoading: x }) => [
|
|
49
|
-
B("div", {
|
|
50
|
-
class: l(["relative cursor-pointer transition-transform active:scale-95 inline-block", { "cursor-default": !e.editable || e.disabled }]),
|
|
51
|
-
onClick: (R) => e.editable && !e.disabled ? d() : null
|
|
52
|
-
}, [
|
|
53
|
-
o(E, {
|
|
54
|
-
src: c.value || void 0,
|
|
55
|
-
fallback: e.fallback,
|
|
56
|
-
alt: e.alt,
|
|
57
|
-
size: e.size,
|
|
58
|
-
rounded: e.rounded,
|
|
59
|
-
class: l(e.className)
|
|
60
|
-
}, null, 8, ["src", "fallback", "alt", "size", "rounded", "class"]),
|
|
61
|
-
e.loading || x ? (n(), r("div", {
|
|
62
|
-
key: 0,
|
|
63
|
-
class: l(["absolute inset-0 flex items-center justify-center bg-black/40 backdrop-blur-[1px] text-white transition-opacity", e.rounded === "full" ? "rounded-full" : "rounded-md"])
|
|
64
|
-
}, [
|
|
65
|
-
o(u, {
|
|
66
|
-
icon: "lucide:loader-2",
|
|
67
|
-
class: "animate-spin w-1/3 h-1/3"
|
|
68
|
-
})
|
|
69
|
-
], 2)) : e.editable && !e.disabled ? (n(), r("div", {
|
|
70
|
-
key: 1,
|
|
71
|
-
class: l(["absolute inset-0 flex items-center justify-center bg-black/40 text-white opacity-0 transition-opacity duration-200 group-hover:opacity-100", e.rounded === "full" ? "rounded-full" : "rounded-md"])
|
|
72
|
-
}, [
|
|
73
|
-
o(u, {
|
|
74
|
-
icon: "lucide:camera",
|
|
75
|
-
class: "w-1/3 h-1/3"
|
|
76
|
-
})
|
|
77
|
-
], 2)) : g("", !0)
|
|
78
|
-
], 10, $)
|
|
79
|
-
]),
|
|
80
|
-
_: 1
|
|
81
|
-
}, 8, ["disabled", "max-size"]),
|
|
82
|
-
c.value && e.editable && !e.disabled && !e.loading ? (n(), r("button", {
|
|
83
|
-
key: 0,
|
|
84
|
-
type: "button",
|
|
85
|
-
class: "absolute -top-1 -right-1 z-10 p-1 bg-background border border-border rounded-full text-muted-foreground shadow-sm hover:text-destructive hover:border-destructive transition-colors opacity-0 group-hover:opacity-100 scale-75 group-hover:scale-100 duration-200 transform",
|
|
86
|
-
onClick: N(m, ["stop"]),
|
|
87
|
-
title: "Remove image"
|
|
32
|
+
};
|
|
33
|
+
return (a, m) => (n(), o("div", E, [
|
|
34
|
+
b("div", {
|
|
35
|
+
class: l(["relative inline-block group", e.rounded === "full" ? "rounded-full" : "rounded-md"])
|
|
88
36
|
}, [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
37
|
+
d(N, {
|
|
38
|
+
src: s.value || void 0,
|
|
39
|
+
fallback: e.fallback,
|
|
40
|
+
alt: e.alt,
|
|
41
|
+
size: e.size,
|
|
42
|
+
rounded: e.rounded,
|
|
43
|
+
class: l(e.className)
|
|
44
|
+
}, null, 8, ["src", "fallback", "alt", "size", "rounded", "class"]),
|
|
45
|
+
d(B, {
|
|
46
|
+
disabled: !e.editable || e.disabled || e.loading,
|
|
47
|
+
"return-format": "base64",
|
|
48
|
+
"file-types": ["image/jpeg", "image/png", "image/webp", "image/gif"],
|
|
49
|
+
"max-size": e.maxSize,
|
|
50
|
+
class: "absolute inset-0",
|
|
51
|
+
onChange: m[0] || (m[0] = (r) => h(r)),
|
|
52
|
+
onError: y
|
|
53
|
+
}, {
|
|
54
|
+
trigger: C(({ trigger: r, isLoading: k }) => [
|
|
55
|
+
b("button", {
|
|
56
|
+
type: "button",
|
|
57
|
+
class: l(["absolute inset-0 cursor-pointer", { "cursor-default": !e.editable || e.disabled }]),
|
|
58
|
+
onClick: (j) => e.editable && !e.disabled ? r() : null
|
|
59
|
+
}, [
|
|
60
|
+
e.loading || k ? (n(), o("div", {
|
|
61
|
+
key: 0,
|
|
62
|
+
class: l(["absolute inset-0 flex items-center justify-center bg-black/40 text-white", e.rounded === "full" ? "rounded-full" : "rounded-md"])
|
|
63
|
+
}, [
|
|
64
|
+
d(u, {
|
|
65
|
+
icon: "lucide:loader-2",
|
|
66
|
+
class: "animate-spin w-1/3 h-1/3"
|
|
67
|
+
})
|
|
68
|
+
], 2)) : e.editable && !e.disabled ? (n(), o("div", {
|
|
69
|
+
key: 1,
|
|
70
|
+
class: l(["absolute inset-0 flex items-center justify-center bg-black/40 text-white opacity-0 group-hover:opacity-100 transition-opacity", e.rounded === "full" ? "rounded-full" : "rounded-md"])
|
|
71
|
+
}, [
|
|
72
|
+
d(u, {
|
|
73
|
+
icon: "lucide:camera",
|
|
74
|
+
class: "w-1/3 h-1/3"
|
|
75
|
+
})
|
|
76
|
+
], 2)) : f("", !0)
|
|
77
|
+
], 10, $)
|
|
78
|
+
]),
|
|
79
|
+
_: 1
|
|
80
|
+
}, 8, ["disabled", "max-size"]),
|
|
81
|
+
s.value && e.editable && !e.disabled && !e.loading ? (n(), o("button", {
|
|
82
|
+
key: 0,
|
|
83
|
+
type: "button",
|
|
84
|
+
class: "absolute -top-1 -right-1 z-10 p-1 bg-background border border-border rounded-full text-muted-foreground shadow-sm hover:text-destructive hover:border-destructive transition-all opacity-0 group-hover:opacity-100 scale-75 group-hover:scale-100",
|
|
85
|
+
onClick: A(c, ["stop"]),
|
|
86
|
+
title: "Remove image"
|
|
87
|
+
}, [
|
|
88
|
+
d(u, {
|
|
89
|
+
icon: "lucide:x",
|
|
90
|
+
class: "w-3 h-3"
|
|
91
|
+
})
|
|
92
|
+
])) : f("", !0)
|
|
93
|
+
], 2)
|
|
94
|
+
]));
|
|
95
95
|
}
|
|
96
96
|
});
|
|
97
97
|
export {
|
|
@@ -26,9 +26,9 @@ const B = { class: "flex items-center space-x-2" }, N = ["aria-checked", "data-s
|
|
|
26
26
|
}, b = {
|
|
27
27
|
xs: "h-3.5 w-3.5",
|
|
28
28
|
sm: "h-4 w-4",
|
|
29
|
-
md: "h-5 w-5",
|
|
30
|
-
lg: "h-
|
|
31
|
-
xl: "h-
|
|
29
|
+
md: "h-4.5 w-4.5",
|
|
30
|
+
lg: "h-5 w-5",
|
|
31
|
+
xl: "h-5.5 w-5.5"
|
|
32
32
|
}, s = {
|
|
33
33
|
xs: "h-2.5 w-2.5",
|
|
34
34
|
sm: "h-3 w-3",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent as w, computed as y, openBlock as t, createElementBlock as i, toDisplayString as
|
|
1
|
+
import { defineComponent as w, computed as y, openBlock as t, createElementBlock as i, toDisplayString as o, createCommentVNode as a, createElementVNode as c, normalizeClass as u, Fragment as V, renderList as _, withKeys as C, withModifiers as B, createVNode as A, createBlock as x } from "vue";
|
|
2
2
|
import m from "../Icon.vue.js";
|
|
3
3
|
const K = { class: "w-full" }, N = {
|
|
4
4
|
key: 0,
|
|
@@ -31,8 +31,8 @@ const K = { class: "w-full" }, N = {
|
|
|
31
31
|
gap: { default: 4 }
|
|
32
32
|
},
|
|
33
33
|
emits: ["update:modelValue", "change"],
|
|
34
|
-
setup(r, { emit:
|
|
35
|
-
const s = r, g =
|
|
34
|
+
setup(r, { emit: h }) {
|
|
35
|
+
const s = r, g = h, n = (l) => Array.isArray(s.modelValue) ? s.modelValue.includes(l) : s.modelValue === l, f = (l) => {
|
|
36
36
|
if (s.disabled || s.options.find((d) => d.id === l)?.disabled) return;
|
|
37
37
|
let e;
|
|
38
38
|
if (s.multiple) {
|
|
@@ -72,16 +72,16 @@ const K = { class: "w-full" }, N = {
|
|
|
72
72
|
});
|
|
73
73
|
return (l, k) => (t(), i("div", K, [
|
|
74
74
|
r.title || r.description ? (t(), i("div", N, [
|
|
75
|
-
r.title ? (t(), i("h3", $,
|
|
76
|
-
r.description ? (t(), i("p", E,
|
|
75
|
+
r.title ? (t(), i("h3", $, o(r.title), 1)) : a("", !0),
|
|
76
|
+
r.description ? (t(), i("p", E, o(r.description), 1)) : a("", !0)
|
|
77
77
|
])) : a("", !0),
|
|
78
78
|
c("div", {
|
|
79
79
|
class: u(["grid", [b.value, v.value]])
|
|
80
80
|
}, [
|
|
81
81
|
(t(!0), i(V, null, _(r.options, (e) => (t(), i("div", {
|
|
82
82
|
key: e.id,
|
|
83
|
-
class: u(["relative flex cursor-pointer rounded-xl border border-border p-4
|
|
84
|
-
|
|
83
|
+
class: u(["relative flex cursor-pointer rounded-xl border border-border p-4 transition-all duration-200 outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2", [
|
|
84
|
+
n(e.id) ? "border-primary bg-accent" : "bg-card hover:border-primary/50 hover:bg-accent",
|
|
85
85
|
r.disabled || e.disabled ? "opacity-50 cursor-not-allowed grayscale" : ""
|
|
86
86
|
]]),
|
|
87
87
|
onClick: (d) => f(e.id),
|
|
@@ -93,7 +93,7 @@ const K = { class: "w-full" }, N = {
|
|
|
93
93
|
c("div", {
|
|
94
94
|
class: u([
|
|
95
95
|
"flex h-10 w-10 items-center justify-center rounded-full transition-colors",
|
|
96
|
-
|
|
96
|
+
n(e.id) ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground"
|
|
97
97
|
])
|
|
98
98
|
}, [
|
|
99
99
|
A(m, {
|
|
@@ -106,26 +106,26 @@ const K = { class: "w-full" }, N = {
|
|
|
106
106
|
c("div", z, [
|
|
107
107
|
c("span", {
|
|
108
108
|
class: u(["font-semibold text-foreground", {
|
|
109
|
-
"text-primary":
|
|
109
|
+
"text-primary": n(e.id)
|
|
110
110
|
}])
|
|
111
|
-
},
|
|
111
|
+
}, o(e.title), 3),
|
|
112
112
|
e.badge ? (t(), i("span", {
|
|
113
113
|
key: 0,
|
|
114
114
|
class: u([
|
|
115
115
|
"inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
|
|
116
|
-
|
|
116
|
+
n(e.id) ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"
|
|
117
117
|
])
|
|
118
|
-
},
|
|
118
|
+
}, o(e.badge), 3)) : a("", !0)
|
|
119
119
|
]),
|
|
120
|
-
e.description ? (t(), i("span", D,
|
|
120
|
+
e.description ? (t(), i("span", D, o(e.description), 1)) : a("", !0)
|
|
121
121
|
])
|
|
122
122
|
]),
|
|
123
|
-
|
|
124
|
-
r.multiple ? (t(),
|
|
123
|
+
n(e.id) ? (t(), i("div", F, [
|
|
124
|
+
r.multiple ? (t(), x(m, {
|
|
125
125
|
key: 0,
|
|
126
126
|
icon: "lucide:check-square",
|
|
127
127
|
class: "h-5 w-5"
|
|
128
|
-
})) : (t(),
|
|
128
|
+
})) : (t(), x(m, {
|
|
129
129
|
key: 1,
|
|
130
130
|
icon: "lucide:check-circle-2",
|
|
131
131
|
class: "h-5 w-5"
|
|
@@ -61,9 +61,9 @@ const F = ["data-state"], L = { class: "flex items-center justify-center" }, U =
|
|
|
61
61
|
};
|
|
62
62
|
return (e, n) => (c(), a("tr", {
|
|
63
63
|
class: u(["border-b border-border/70 transition-colors data-[state=selected]:bg-muted h-full", [
|
|
64
|
-
t.hoverable ? "hover:bg-muted/
|
|
64
|
+
t.hoverable ? "hover:bg-muted/80" : "",
|
|
65
65
|
t.striped && t.index % 2 === 1 ? "bg-muted/20" : "bg-background",
|
|
66
|
-
t.isSelected ? "bg-muted
|
|
66
|
+
t.isSelected ? "bg-muted! hover:bg-muted/30" : "",
|
|
67
67
|
"group"
|
|
68
68
|
]]),
|
|
69
69
|
"data-state": t.isSelected ? "selected" : void 0,
|