vlite3 1.4.4 → 1.4.6

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.
Files changed (102) hide show
  1. package/components/AppShell/AppShellLayoutStorefront.vue.d.ts +4 -17
  2. package/components/AppShell/AppShellLayoutStorefront.vue.js +116 -152
  3. package/components/AvatarUploader/AvatarUploader.vue.d.ts +1 -1
  4. package/components/AvatarUploader/AvatarUploader.vue.js +1 -1
  5. package/components/Cart/Cart.vue.js +242 -0
  6. package/components/Cart/Cart.vue2.js +4 -0
  7. package/components/Cart/CartCouponInput.vue.js +176 -0
  8. package/components/Cart/CartCouponInput.vue2.js +4 -0
  9. package/components/Cart/CartEmptyState.vue.js +48 -0
  10. package/components/Cart/CartEmptyState.vue2.js +4 -0
  11. package/components/Cart/CartLineItem.vue.js +341 -0
  12. package/components/Cart/CartLineItem.vue2.js +4 -0
  13. package/components/Cart/CartSummary.vue.js +157 -0
  14. package/components/Cart/CartSummary.vue2.js +4 -0
  15. package/components/Cart/CartVariant1.vue.js +156 -0
  16. package/components/Cart/CartVariant1.vue2.js +4 -0
  17. package/components/Cart/CartVariant2.vue.js +154 -0
  18. package/components/Cart/CartVariant2.vue2.js +4 -0
  19. package/components/Cart/CartVariant3.vue.js +192 -0
  20. package/components/Cart/CartVariant3.vue2.js +4 -0
  21. package/components/Cart/CartVariant4.vue.js +145 -0
  22. package/components/Cart/CartVariant4.vue2.js +4 -0
  23. package/components/Cart/composables/useCart.d.ts +46 -0
  24. package/components/Cart/composables/useCart.js +110 -0
  25. package/components/Cart/composables/useCartCalculation.js +145 -0
  26. package/components/Cart/index.d.ts +2 -0
  27. package/components/CategoryManager/CategoryManager.vue.js +3 -3
  28. package/components/CategoryManager/CategoryManager.vue2.js +225 -249
  29. package/components/CategoryManager/utils.d.ts +3 -0
  30. package/components/CategoryManager/utils.js +31 -0
  31. package/components/CategoryMenu/CategoryMenu.vue.d.ts +2 -0
  32. package/components/CategoryMenu/CategoryMenu.vue.js +46 -40
  33. package/components/CategoryMenu/CategoryMenuVariant1.vue.d.ts +5 -1
  34. package/components/CategoryMenu/CategoryMenuVariant1.vue.js +5 -144
  35. package/components/CategoryMenu/CategoryMenuVariant1.vue2.js +220 -2
  36. package/components/CategoryMenu/CategoryMenuVariant2.vue.d.ts +5 -1
  37. package/components/CategoryMenu/CategoryMenuVariant2.vue.js +5 -160
  38. package/components/CategoryMenu/CategoryMenuVariant2.vue2.js +235 -2
  39. package/components/CategoryMenu/types.d.ts +5 -2
  40. package/components/Chat/ChatInterface.vue.js +1 -1
  41. package/components/Comment/CommentEditor.vue.js +1 -1
  42. package/components/Dropdown/Dropdown.vue.d.ts +1 -0
  43. package/components/Dropdown/Dropdown.vue.js +31 -29
  44. package/components/FilePicker/FilePickerDropzone.vue.d.ts +27 -0
  45. package/components/FilePicker/FilePickerDropzone.vue.js +117 -0
  46. package/components/FilePicker/FilePickerDropzone.vue2.js +4 -0
  47. package/components/FilePicker/FilePickerInput.vue.d.ts +22 -0
  48. package/components/FilePicker/FilePickerInput.vue.js +147 -0
  49. package/components/FilePicker/FilePickerInput.vue2.js +4 -0
  50. package/components/FilePicker/FilePreview.vue.d.ts +21 -0
  51. package/components/FilePicker/FilePreview.vue.js +95 -0
  52. package/components/FilePicker/FilePreview.vue2.js +4 -0
  53. package/components/FilePicker/composables/useFileProcessing.d.ts +65 -0
  54. package/components/FilePicker/composables/useFileProcessing.js +141 -0
  55. package/components/FilePicker/index.d.ts +2 -2
  56. package/components/FilePicker/{FilePicker.vue.d.ts → index.vue.d.ts} +11 -18
  57. package/components/FilePicker/index.vue.js +131 -0
  58. package/components/FilePicker/index.vue2.js +4 -0
  59. package/components/FilePicker/types.d.ts +17 -0
  60. package/components/FilePicker/utils.d.ts +23 -0
  61. package/components/FilePicker/utils.js +37 -0
  62. package/components/Form/AccordionView.vue.d.ts +26 -0
  63. package/components/Form/AccordionView.vue.js +219 -0
  64. package/components/Form/AccordionView.vue2.js +4 -0
  65. package/components/Form/FormField.vue.js +3 -3
  66. package/components/Form/FormFields.vue.js +2 -2
  67. package/components/Form/TableRow.vue.d.ts +18 -0
  68. package/components/Form/TableRow.vue.js +88 -0
  69. package/components/Form/TableRow.vue2.js +4 -0
  70. package/components/Form/TableView.vue.d.ts +23 -0
  71. package/components/Form/TableView.vue.js +88 -0
  72. package/components/Form/TableView.vue2.js +4 -0
  73. package/components/Form/composables/useCustomFieldRows.d.ts +52 -0
  74. package/components/Form/composables/useCustomFieldRows.js +77 -0
  75. package/components/Form/index.d.ts +1 -1
  76. package/components/Form/{CustomFields.vue.d.ts → index.vue.d.ts} +8 -5
  77. package/components/Form/index.vue.js +7 -0
  78. package/components/Form/index.vue2.js +141 -0
  79. package/components/Form/rowHelpers.d.ts +45 -0
  80. package/components/Form/rowHelpers.js +40 -0
  81. package/components/Form/types.d.ts +3 -0
  82. package/components/IconPicker.vue.d.ts +2 -2
  83. package/components/Modal.vue.d.ts +2 -0
  84. package/components/Modal.vue.js +1 -1
  85. package/components/Modal.vue2.js +30 -28
  86. package/components/Screen/ScreenFilter.vue.js +4 -3
  87. package/components/SidePanel.vue.d.ts +2 -0
  88. package/components/SidePanel.vue.js +1 -1
  89. package/components/SidePanel.vue2.js +25 -23
  90. package/components/SidebarMenu/SidebarMenu.vue.js +145 -128
  91. package/components/ThumbnailSelector/ThumbnailSelector.vue.js +1 -1
  92. package/components/ThumbnailSelector/ThumbnailSelector.vue2.js +1 -1
  93. package/components/index.d.ts +2 -1
  94. package/core/config.d.ts +6 -6
  95. package/index.d.ts +1 -0
  96. package/index.js +328 -307
  97. package/package.json +1 -1
  98. package/style.css +1 -1
  99. package/components/FilePicker/FilePicker.vue.js +0 -361
  100. package/components/FilePicker/FilePicker.vue2.js +0 -4
  101. package/components/Form/CustomFields.vue.js +0 -7
  102. package/components/Form/CustomFields.vue2.js +0 -261
@@ -0,0 +1,117 @@
1
+ import { defineComponent as F, ref as u, computed as D, openBlock as n, createElementBlock as t, normalizeClass as k, createElementVNode as o, createBlock as s, toDisplayString as d, createTextVNode as T, createCommentVNode as g, Fragment as w, renderList as L, unref as B, createVNode as P } from "vue";
2
+ import f from "../Icon.vue.js";
3
+ import R from "../Button.vue.js";
4
+ import p from "./FilePreview.vue.js";
5
+ import { isImageFile as C } from "./utils.js";
6
+ const N = ["data-testid"], S = { class: "p-3 bg-muted rounded-full text-muted-foreground" }, V = { class: "space-y-1" }, z = { class: "text-sm font-medium text-foreground" }, A = { class: "text-primary hover:underline" }, M = {
7
+ key: 0,
8
+ class: "text-xs text-muted-foreground"
9
+ }, $ = {
10
+ key: 1,
11
+ class: "space-y-2"
12
+ }, j = {
13
+ key: 0,
14
+ class: "flex gap-2"
15
+ }, H = /* @__PURE__ */ F({
16
+ __name: "FilePickerDropzone",
17
+ props: {
18
+ displayFiles: {},
19
+ hasValue: { type: Boolean },
20
+ multiSelect: { type: Boolean },
21
+ maxFiles: {},
22
+ loading: { type: Boolean },
23
+ isProcessing: { type: Boolean },
24
+ disabled: { type: Boolean },
25
+ allowRename: { type: Boolean },
26
+ fileTypes: {},
27
+ displayText: {},
28
+ dragAndDropLabel: {},
29
+ enterFileNameLabel: {},
30
+ renameFileLabel: {},
31
+ addMoreLabel: {},
32
+ dataTestid: {},
33
+ getPreviewSrc: { type: Function },
34
+ onTrigger: { type: Function },
35
+ onRemove: { type: Function },
36
+ onRename: { type: Function },
37
+ onDrop: { type: Function }
38
+ },
39
+ setup(e) {
40
+ const a = e, l = u(!1), y = u(null), b = (i) => {
41
+ i.preventDefault(), !(a.disabled || a.loading) && (l.value = !0);
42
+ }, v = (i) => {
43
+ i.preventDefault(), l.value = !1;
44
+ }, x = (i) => {
45
+ i.preventDefault(), l.value = !1, !(a.disabled || a.loading || a.isProcessing) && i.dataTransfer?.files && a.onDrop(i.dataTransfer.files);
46
+ }, h = D(() => a.multiSelect ? a.maxFiles ? a.displayFiles.length < a.maxFiles : !0 : !1);
47
+ return (i, c) => (n(), t("div", {
48
+ ref_key: "containerRef",
49
+ ref: y,
50
+ class: "relative",
51
+ "data-testid": e.dataTestid,
52
+ onDragover: b,
53
+ onDragleave: v,
54
+ onDrop: x
55
+ }, [
56
+ e.hasValue ? (n(), t("div", $, [
57
+ (n(!0), t(w, null, L(e.displayFiles, (r, m) => (n(), s(p, {
58
+ key: m,
59
+ file: r,
60
+ index: m,
61
+ "allow-rename": e.allowRename,
62
+ disabled: e.disabled,
63
+ loading: e.loading,
64
+ "is-processing": e.isProcessing,
65
+ "multi-select": e.multiSelect,
66
+ "enter-file-name-label": e.enterFileNameLabel,
67
+ "rename-file-label": e.renameFileLabel,
68
+ "get-preview-src": e.getPreviewSrc,
69
+ "is-image": B(C),
70
+ "on-remove": e.onRemove,
71
+ "on-rename": e.onRename,
72
+ "on-trigger": e.onTrigger
73
+ }, null, 8, ["file", "index", "allow-rename", "disabled", "loading", "is-processing", "multi-select", "enter-file-name-label", "rename-file-label", "get-preview-src", "is-image", "on-remove", "on-rename", "on-trigger"]))), 128)),
74
+ h.value ? (n(), t("div", j, [
75
+ P(R, {
76
+ size: "sm",
77
+ variant: "outline",
78
+ icon: "lucide:plus",
79
+ text: e.addMoreLabel,
80
+ disabled: e.disabled || e.loading || e.isProcessing,
81
+ onClick: e.onTrigger
82
+ }, null, 8, ["text", "disabled", "onClick"])
83
+ ])) : g("", !0)
84
+ ])) : (n(), t("div", {
85
+ key: 0,
86
+ class: k(["border-2 bg-body border-dashed border-border rounded-lg p-6 transition-all duration-200 ease-in-out cursor-pointer flex flex-col items-center justify-center text-center gap-2", [
87
+ l.value ? "border-primary bg-primary/5" : "hover:border-primary/50",
88
+ e.disabled || e.loading || e.isProcessing ? "opacity-50 cursor-not-allowed" : ""
89
+ ]]),
90
+ onClick: c[0] || (c[0] = //@ts-ignore
91
+ (...r) => e.onTrigger && e.onTrigger(...r))
92
+ }, [
93
+ o("div", S, [
94
+ e.loading || e.isProcessing ? (n(), s(f, {
95
+ key: 0,
96
+ icon: "lucide:loader-2",
97
+ class: "w-6 h-6 animate-spin"
98
+ })) : (n(), s(f, {
99
+ key: 1,
100
+ icon: "lucide:upload-cloud",
101
+ class: "w-6 h-6"
102
+ }))
103
+ ]),
104
+ o("div", V, [
105
+ o("p", z, [
106
+ o("span", A, d(e.displayText), 1),
107
+ T(" " + d(e.dragAndDropLabel), 1)
108
+ ]),
109
+ e.fileTypes.length ? (n(), t("p", M, d(e.fileTypes.join(", ")), 1)) : g("", !0)
110
+ ])
111
+ ], 2))
112
+ ], 40, N));
113
+ }
114
+ });
115
+ export {
116
+ H as default
117
+ };
@@ -0,0 +1,4 @@
1
+ import f from "./FilePickerDropzone.vue.js";
2
+ export {
3
+ f as default
4
+ };
@@ -0,0 +1,22 @@
1
+ import { FilePickerValue } from './types';
2
+ import { InputSize, InputRounded } from '../../types';
3
+ interface Props {
4
+ displayFiles: FilePickerValue[];
5
+ firstDisplayFile?: FilePickerValue;
6
+ hasValue: boolean;
7
+ multiSelect: boolean;
8
+ loading: boolean;
9
+ isProcessing: boolean;
10
+ disabled: boolean;
11
+ displayPlaceholder: string;
12
+ acceptedFileSummary: string;
13
+ size: InputSize;
14
+ rounded: InputRounded;
15
+ getPreviewSrc: (file: FilePickerValue) => string;
16
+ dataTestid: string;
17
+ triggerAriaLabel: string;
18
+ onTrigger: () => void;
19
+ onClear: () => void;
20
+ }
21
+ declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
22
+ export default _default;
@@ -0,0 +1,147 @@
1
+ import { defineComponent as w, computed as o, openBlock as s, createElementBlock as r, createElementVNode as a, withKeys as y, withModifiers as c, normalizeClass as u, createVNode as m, unref as k, toDisplayString as g, createBlock as F, createCommentVNode as x } from "vue";
2
+ import d from "../Icon.vue.js";
3
+ import { formatFileSize as S, getFileIcon as p } from "./utils.js";
4
+ const z = { class: "relative" }, C = ["aria-disabled", "aria-label", "data-testid"], P = {
5
+ key: 0,
6
+ class: "flex min-w-0 flex-1 items-center gap-2.5"
7
+ }, T = ["src", "alt"], B = { class: "min-w-0 flex-1 flex flex-col contain-inline-size" }, V = { class: "truncate min-w-0 font-medium leading-tight text-foreground" }, D = { class: "truncate min-w-0 text-[11px] leading-tight text-muted-foreground" }, N = {
8
+ key: 1,
9
+ class: "flex min-w-0 flex-1 items-center gap-2 text-muted-foreground"
10
+ }, j = { class: "truncate min-w-0 flex-1" }, $ = {
11
+ key: 0,
12
+ class: "absolute right-3 top-1/2 -translate-y-1/2 flex items-center justify-center gap-2 bg-background"
13
+ }, K = /* @__PURE__ */ w({
14
+ __name: "FilePickerInput",
15
+ props: {
16
+ displayFiles: {},
17
+ firstDisplayFile: {},
18
+ hasValue: { type: Boolean },
19
+ multiSelect: { type: Boolean },
20
+ loading: { type: Boolean },
21
+ isProcessing: { type: Boolean },
22
+ disabled: { type: Boolean },
23
+ displayPlaceholder: {},
24
+ acceptedFileSummary: {},
25
+ size: {},
26
+ rounded: {},
27
+ getPreviewSrc: { type: Function },
28
+ dataTestid: {},
29
+ triggerAriaLabel: {},
30
+ onTrigger: { type: Function },
31
+ onClear: { type: Function }
32
+ },
33
+ setup(e) {
34
+ const n = e, b = o(() => {
35
+ const i = "group flex w-full min-w-0 items-center bg-background text-sm ring-offset-background transition-all focus-visible:outline-none cursor-pointer", t = {
36
+ sm: "min-h-8 px-2 py-1 text-xs gap-2",
37
+ md: "min-h-10 px-3 py-1.5 text-sm gap-2.5",
38
+ lg: "min-h-12 px-3 py-2 text-base gap-3"
39
+ }, l = {
40
+ none: "rounded-none",
41
+ sm: "rounded-sm",
42
+ md: "rounded-md",
43
+ lg: "rounded-lg",
44
+ xl: "rounded-xl",
45
+ "2xl": "rounded-2xl",
46
+ full: "rounded-full"
47
+ };
48
+ return [
49
+ i,
50
+ "border border-input focus-visible:border-primary",
51
+ t[n.size],
52
+ l[n.rounded],
53
+ "pr-10 text-left",
54
+ n.disabled ? "cursor-not-allowed opacity-50" : ""
55
+ ].join(" ");
56
+ }), f = o(() => ({
57
+ sm: "h-6 w-6 rounded",
58
+ md: "h-7 w-7 rounded-md",
59
+ lg: "h-8 w-8 rounded-md"
60
+ })[n.size]), h = o(() => {
61
+ if (!n.hasValue) return "";
62
+ const i = n.displayFiles, t = i[0]?.fileName || "";
63
+ return !n.multiSelect || i.length <= 1 ? t : `${t} +${i.length - 1}`;
64
+ }), v = o(() => {
65
+ const i = n.displayFiles;
66
+ if (!i.length) return n.acceptedFileSummary;
67
+ if (n.multiSelect && i.length > 1) return `${i.length} files selected`;
68
+ const t = i[0];
69
+ return S(t.fileSize) || t.fileType || "";
70
+ });
71
+ return (i, t) => (s(), r("div", z, [
72
+ a("div", {
73
+ role: "button",
74
+ tabindex: "0",
75
+ "aria-disabled": e.disabled || e.loading || e.isProcessing,
76
+ "aria-label": e.triggerAriaLabel,
77
+ class: u(b.value),
78
+ "data-testid": e.dataTestid,
79
+ onClick: t[0] || (t[0] = //@ts-ignore
80
+ (...l) => e.onTrigger && e.onTrigger(...l)),
81
+ onKeydown: [
82
+ t[1] || (t[1] = y(c(
83
+ //@ts-ignore
84
+ (...l) => e.onTrigger && e.onTrigger(...l),
85
+ ["prevent"]
86
+ ), ["enter"])),
87
+ t[2] || (t[2] = y(c(
88
+ //@ts-ignore
89
+ (...l) => e.onTrigger && e.onTrigger(...l),
90
+ ["prevent"]
91
+ ), ["space"]))
92
+ ]
93
+ }, [
94
+ e.hasValue && e.firstDisplayFile ? (s(), r("div", P, [
95
+ e.getPreviewSrc(e.firstDisplayFile) ? (s(), r("img", {
96
+ key: 0,
97
+ src: e.getPreviewSrc(e.firstDisplayFile),
98
+ alt: e.firstDisplayFile.fileName,
99
+ class: u(["shrink-0 border border-border bg-muted object-cover", f.value])
100
+ }, null, 10, T)) : (s(), r("div", {
101
+ key: 1,
102
+ class: u(["shrink-0 border border-primary/15 bg-primary/10 text-primary flex items-center justify-center", f.value])
103
+ }, [
104
+ m(d, {
105
+ icon: k(p)(e.firstDisplayFile),
106
+ class: "h-4 w-4"
107
+ }, null, 8, ["icon"])
108
+ ], 2)),
109
+ a("div", B, [
110
+ a("p", V, g(h.value), 1),
111
+ a("p", D, g(v.value), 1)
112
+ ])
113
+ ])) : (s(), r("div", N, [
114
+ m(d, {
115
+ icon: "lucide:upload",
116
+ class: "h-4 w-4 shrink-0"
117
+ }),
118
+ a("span", j, g(e.displayPlaceholder), 1)
119
+ ]))
120
+ ], 42, C),
121
+ e.loading || e.isProcessing || e.hasValue && !e.disabled ? (s(), r("div", $, [
122
+ e.loading || e.isProcessing ? (s(), F(d, {
123
+ key: 0,
124
+ icon: "lucide:loader-2",
125
+ class: "h-4 w-4 animate-spin text-muted-foreground"
126
+ })) : e.hasValue && !e.disabled ? (s(), r("button", {
127
+ key: 1,
128
+ type: "button",
129
+ class: "text-muted-foreground hover:text-foreground focus:outline-none",
130
+ onClick: t[3] || (t[3] = c(
131
+ //@ts-ignore
132
+ (...l) => e.onClear && e.onClear(...l),
133
+ ["stop"]
134
+ ))
135
+ }, [
136
+ m(d, {
137
+ icon: "lucide:x-circle",
138
+ class: "h-4 w-4"
139
+ })
140
+ ])) : x("", !0)
141
+ ])) : x("", !0)
142
+ ]));
143
+ }
144
+ });
145
+ export {
146
+ K as default
147
+ };
@@ -0,0 +1,4 @@
1
+ import f from "./FilePickerInput.vue.js";
2
+ export {
3
+ f as default
4
+ };
@@ -0,0 +1,21 @@
1
+ import { FilePickerValue } from './types';
2
+ interface Props {
3
+ file: FilePickerValue;
4
+ index: number;
5
+ allowRename: boolean;
6
+ disabled: boolean;
7
+ loading: boolean;
8
+ isProcessing: boolean;
9
+ multiSelect: boolean;
10
+ enterFileNameLabel: string;
11
+ renameFileLabel: string;
12
+ getPreviewSrc: (file: FilePickerValue) => string;
13
+ isImage: (file: FilePickerValue) => boolean;
14
+ onRemove: (index: number) => void;
15
+ onRename: (index: number, newName: string) => void;
16
+ onTrigger: () => void;
17
+ }
18
+ declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
19
+ fileNameInput: HTMLInputElement;
20
+ }, HTMLDivElement>;
21
+ export default _default;
@@ -0,0 +1,95 @@
1
+ import { defineComponent as b, ref as h, computed as u, openBlock as n, createElementBlock as r, normalizeClass as p, createElementVNode as t, createVNode as f, toDisplayString as s, withModifiers as a, unref as w, createBlock as g, createCommentVNode as y } from "vue";
2
+ import d from "../Icon.vue.js";
3
+ import k from "../Button.vue.js";
4
+ import { formatFileSize as F } from "./utils.js";
5
+ const N = { class: "shrink-0 mr-3" }, B = { class: "p-2 bg-primary-light rounded text-primary-fg-light" }, C = { class: "flex-1 min-w-0 flex flex-col items-start overflow-hidden contain-inline-size" }, R = {
6
+ key: 0,
7
+ class: "inline-flex items-center group/rename w-fit max-w-full mb-0.5"
8
+ }, P = { class: "grid relative w-fit max-w-full items-center -ml-1" }, S = { class: "invisible whitespace-pre col-start-1 row-start-1 text-sm font-medium px-1 py-0.5 max-w-full overflow-hidden text-ellipsis" }, z = ["value", "placeholder"], L = ["title"], I = {
9
+ key: 1,
10
+ class: "text-sm font-medium text-foreground truncate w-full min-w-0"
11
+ }, $ = { class: "text-xs text-muted-foreground -mt-1" }, V = { class: "shrink-0 ml-3 flex gap-2 items-center" }, q = /* @__PURE__ */ b({
12
+ __name: "FilePreview",
13
+ props: {
14
+ file: {},
15
+ index: {},
16
+ allowRename: { type: Boolean },
17
+ disabled: { type: Boolean },
18
+ loading: { type: Boolean },
19
+ isProcessing: { type: Boolean },
20
+ multiSelect: { type: Boolean },
21
+ enterFileNameLabel: {},
22
+ renameFileLabel: {},
23
+ getPreviewSrc: { type: Function },
24
+ isImage: { type: Function },
25
+ onRemove: { type: Function },
26
+ onRename: { type: Function },
27
+ onTrigger: { type: Function }
28
+ },
29
+ setup(e) {
30
+ const o = e, c = h(null), x = u(() => o.file.fileName || o.enterFileNameLabel), m = u(
31
+ () => !o.multiSelect && !o.disabled && !o.loading && !o.isProcessing
32
+ ), v = () => {
33
+ c.value?.focus();
34
+ };
35
+ return (E, i) => (n(), r("div", {
36
+ class: p(["relative flex items-center min-w-0 p-3 border border-border rounded-lg bg-body transition-colors group", m.value ? "cursor-pointer hover:border-primary/50" : ""]),
37
+ onClick: i[3] || (i[3] = (l) => m.value ? e.onTrigger() : null)
38
+ }, [
39
+ t("div", N, [
40
+ t("div", B, [
41
+ f(d, {
42
+ icon: "lucide:file-text",
43
+ class: "w-5 h-5"
44
+ })
45
+ ])
46
+ ]),
47
+ t("div", C, [
48
+ e.allowRename && !e.disabled && !e.loading && !e.isProcessing ? (n(), r("div", R, [
49
+ t("div", P, [
50
+ t("span", S, s(x.value), 1),
51
+ t("input", {
52
+ ref_key: "fileNameInput",
53
+ ref: c,
54
+ value: e.file.fileName,
55
+ onClick: i[0] || (i[0] = a(() => {
56
+ }, ["stop"])),
57
+ onInput: i[1] || (i[1] = (l) => e.onRename(e.index, l.target.value)),
58
+ class: "col-start-1 row-start-1 w-auto min-w-[2ch] text-sm font-medium text-foreground bg-transparent border-b border-transparent hover:border-border focus:border-primary outline-none transition-colors py-0.5 px-1",
59
+ placeholder: e.enterFileNameLabel
60
+ }, null, 40, z)
61
+ ]),
62
+ t("div", {
63
+ class: "shrink-0 ml-1 text-muted-foreground/50 group-hover/rename:text-foreground transition-colors cursor-text",
64
+ title: e.renameFileLabel,
65
+ onClick: a(v, ["stop"])
66
+ }, [
67
+ f(d, {
68
+ icon: "lucide:pencil",
69
+ class: "w-3 h-3"
70
+ })
71
+ ], 8, L)
72
+ ])) : (n(), r("p", I, s(e.file.fileName), 1)),
73
+ t("p", $, s(w(F)(e.file.fileSize)), 1)
74
+ ]),
75
+ t("div", V, [
76
+ e.loading || e.isProcessing ? (n(), g(d, {
77
+ key: 0,
78
+ icon: "lucide:loader-2",
79
+ class: "w-4 h-4 animate-spin text-primary"
80
+ })) : e.disabled ? y("", !0) : (n(), g(k, {
81
+ key: 1,
82
+ size: "xs",
83
+ variant: "ghost",
84
+ icon: "lucide:x",
85
+ rounded: "full",
86
+ class: "text-muted-foreground hover:text-destructive hover:bg-destructive/10",
87
+ onClick: i[2] || (i[2] = a((l) => e.onRemove(e.index), ["stop"]))
88
+ }))
89
+ ])
90
+ ], 2));
91
+ }
92
+ });
93
+ export {
94
+ q as default
95
+ };
@@ -0,0 +1,4 @@
1
+ import f from "./FilePreview.vue.js";
2
+ export {
3
+ f as default
4
+ };
@@ -0,0 +1,65 @@
1
+ import { Ref, ComputedRef } from 'vue';
2
+ import { FilePickerValue, FilePickerModelValue } from '../types';
3
+ /**
4
+ * Getter functions for each reactive prop. Using getters (rather than a
5
+ * snapshot object) is what keeps the composable reactive: the parent
6
+ * passes `() => props.modelValue`, and the composable's `computed`s call
7
+ * the getter to read the current value at evaluation time, so Vue's
8
+ * dependency tracking sees the actual reactive read.
9
+ *
10
+ * If we had captured the values directly (e.g. `modelValue: props.modelValue`),
11
+ * the composable's computeds would read a stale snapshot — props.modelValue
12
+ * never changes inside the composable because it's a plain value, not a
13
+ * reactive proxy. That was the bug in the previous revision: a file was
14
+ * picked, the emit went out, but the composable's `displayFiles` never
15
+ * updated because it was reading a frozen snapshot of the original null
16
+ * value.
17
+ */
18
+ export interface UseFileProcessingGetters {
19
+ modelValue: () => FilePickerModelValue;
20
+ multiSelect: () => boolean;
21
+ fileTypes: () => string[];
22
+ maxSize: () => number | undefined;
23
+ maxFiles: () => number | undefined;
24
+ returnFormat: () => 'file' | 'base64';
25
+ disabled: () => boolean;
26
+ loading: () => boolean;
27
+ unknownFileFallback: () => string;
28
+ }
29
+ export interface UseFileProcessingReturn {
30
+ /** Normalized list of files for rendering. */
31
+ displayFiles: ComputedRef<FilePickerValue[]>;
32
+ /** True if a value is present. */
33
+ hasValue: ComputedRef<boolean>;
34
+ /** The first file (used by the input variant for the trigger button). */
35
+ firstDisplayFile: ComputedRef<FilePickerValue | undefined>;
36
+ /** Whether async processing is in-flight. */
37
+ isProcessing: Ref<boolean>;
38
+ /** Imperative API */
39
+ triggerInput: (fileInput: HTMLInputElement | null) => void;
40
+ processFiles: (fileList: FileList) => Promise<void>;
41
+ removeFile: (index: number) => void;
42
+ clearAll: () => void;
43
+ handleFileNameChange: (index: number, newName: string) => void;
44
+ /** Comma-separated file-types for the `accept` attribute on the hidden <input>. */
45
+ acceptAttribute: ComputedRef<string>;
46
+ /** Summary for the trigger meta line, e.g. ".png, .jpg" or "1.2 MB". */
47
+ acceptedFileSummary: ComputedRef<string>;
48
+ /** Preview src for image files; empty string for non-images. */
49
+ getPreviewSrc: (file: FilePickerValue) => string;
50
+ }
51
+ /**
52
+ * Owns the FilePicker's reactive state and the imperative operations that
53
+ * mutate the model value (via emitted events). The orchestrator component
54
+ * passes the result of this composable down to FilePickerInput and
55
+ * FilePickerDropzone so neither subcomponent has to know about processing
56
+ * logic — they just render props and call back into the API.
57
+ *
58
+ * Emits are passed in as a callback so this composable stays UI-framework
59
+ * agnostic (the same pattern can be unit-tested without mounting a component).
60
+ */
61
+ export declare const useFileProcessing: (get: UseFileProcessingGetters, emit: {
62
+ (e: "update:modelValue", value: FilePickerModelValue): void;
63
+ (e: "change", value: FilePickerModelValue): void;
64
+ (e: "error", error: string): void;
65
+ }) => UseFileProcessingReturn;
@@ -0,0 +1,141 @@
1
+ import { ref as x, onBeforeUnmount as T, computed as f } from "vue";
2
+ import { normalizeForDisplay as U, isImageFile as j, readFileAsBase64 as z } from "../utils.js";
3
+ const N = (e, o) => {
4
+ const c = x(!1), p = /* @__PURE__ */ new WeakMap(), m = /* @__PURE__ */ new Set();
5
+ T(() => {
6
+ m.forEach((l) => URL.revokeObjectURL(l)), m.clear();
7
+ });
8
+ const v = f(() => e.fileTypes().join(",")), b = f(() => {
9
+ const l = e.modelValue();
10
+ return Array.isArray(l) ? l.length > 0 : l !== null;
11
+ }), y = f(() => {
12
+ const l = e.modelValue(), s = [];
13
+ return Array.isArray(l) ? s.push(...l) : l && s.push(l), s.map((r) => U(r, e.unknownFileFallback()));
14
+ }), S = f(() => y.value[0]), V = f(() => e.fileTypes().join(", "));
15
+ return {
16
+ displayFiles: y,
17
+ hasValue: b,
18
+ firstDisplayFile: S,
19
+ isProcessing: c,
20
+ triggerInput: (l) => {
21
+ if (!(e.disabled() || e.loading() || c.value)) {
22
+ if (e.multiSelect() && e.maxFiles()) {
23
+ const s = e.modelValue();
24
+ if ((Array.isArray(s) ? s.length : s ? 1 : 0) >= e.maxFiles()) {
25
+ o("error", `Maximum ${e.maxFiles()} files allowed`);
26
+ return;
27
+ }
28
+ }
29
+ l?.click();
30
+ }
31
+ },
32
+ processFiles: async (l) => {
33
+ if (l.length === 0) return;
34
+ c.value = !0;
35
+ const s = [], r = [], a = Array.from(l);
36
+ let d = e.multiSelect() ? a : [a[0]];
37
+ if (e.multiSelect() && e.maxFiles()) {
38
+ const i = e.modelValue(), n = Array.isArray(i) ? i.length : i ? 1 : 0, t = e.maxFiles() - n;
39
+ if (t <= 0) {
40
+ o("error", `Maximum ${e.maxFiles()} files allowed`), c.value = !1;
41
+ return;
42
+ }
43
+ d.length > t && (r.push(`Only ${t} more file(s) allowed. Maximum ${e.maxFiles()} files.`), d = d.slice(0, t));
44
+ }
45
+ try {
46
+ for (const i of d) {
47
+ const n = e.fileTypes();
48
+ if (n.length > 0 && !n.some((u) => {
49
+ if (u.startsWith(".")) return i.name.toLowerCase().endsWith(u.toLowerCase());
50
+ if (u.endsWith("/*")) {
51
+ const w = u.split("/")[0];
52
+ return i.type.startsWith(w);
53
+ }
54
+ return i.type === u;
55
+ })) {
56
+ r.push(`File type not allowed: ${i.name}`);
57
+ continue;
58
+ }
59
+ let t = !1;
60
+ const h = e.maxSize();
61
+ h && i.size > h && (r.push(`File too large: ${i.name}`), t = !0);
62
+ let F = "";
63
+ if (e.returnFormat() === "base64" && !t)
64
+ try {
65
+ F = await z(i);
66
+ } catch (A) {
67
+ console.error("Base64 read failed", A);
68
+ }
69
+ s.push({
70
+ fileName: i.name,
71
+ fileType: i.type,
72
+ fileSize: i.size,
73
+ file: i,
74
+ base64: F
75
+ });
76
+ }
77
+ if (r.length > 0 && o("error", r.join("; ")), s.length > 0) {
78
+ let i;
79
+ if (e.multiSelect()) {
80
+ const n = e.modelValue();
81
+ i = [...Array.isArray(n) ? n : n ? [n] : [], ...s];
82
+ } else
83
+ i = s[0];
84
+ o("update:modelValue", i), o("change", i);
85
+ }
86
+ } catch (i) {
87
+ console.error("Error processing files:", i), o("error", "Failed to process files");
88
+ } finally {
89
+ c.value = !1;
90
+ }
91
+ },
92
+ removeFile: (l) => {
93
+ if (e.disabled() || e.loading()) return;
94
+ const s = e.modelValue();
95
+ if (e.multiSelect() && Array.isArray(s)) {
96
+ const r = [...s];
97
+ r.splice(l, 1), o("update:modelValue", r), o("change", r);
98
+ } else
99
+ o("update:modelValue", null), o("change", null);
100
+ },
101
+ clearAll: () => {
102
+ e.disabled() || e.loading() || (o("update:modelValue", null), o("change", null));
103
+ },
104
+ handleFileNameChange: (l, s) => {
105
+ if (e.disabled() || e.loading() || c.value) return;
106
+ const r = e.modelValue();
107
+ let a;
108
+ e.multiSelect() && Array.isArray(r) ? (a = [...r], typeof a[l] == "object" && a[l] !== null ? a[l] = { ...a[l], fileName: s } : typeof a[l] == "string" && (a[l] = {
109
+ fileName: s,
110
+ fileType: "unknown",
111
+ fileSize: 0,
112
+ file: null,
113
+ base64: a[l],
114
+ isUrl: !0
115
+ })) : r && typeof r == "object" && !Array.isArray(r) ? a = { ...r, fileName: s } : typeof r == "string" && (a = {
116
+ fileName: s,
117
+ fileType: "unknown",
118
+ fileSize: 0,
119
+ file: null,
120
+ base64: r,
121
+ isUrl: !0
122
+ }), a !== void 0 && (o("update:modelValue", a), o("change", a));
123
+ },
124
+ acceptAttribute: v,
125
+ acceptedFileSummary: V,
126
+ getPreviewSrc: (l) => {
127
+ if (!j(l)) return "";
128
+ if (l.base64?.startsWith("data:image/") || l.isUrl) return l.base64;
129
+ if (typeof File < "u" && l.file instanceof File) {
130
+ const s = p.get(l.file);
131
+ if (s) return s;
132
+ const r = URL.createObjectURL(l.file);
133
+ return p.set(l.file, r), m.add(r), r;
134
+ }
135
+ return "";
136
+ }
137
+ };
138
+ };
139
+ export {
140
+ N as useFileProcessing
141
+ };
@@ -1,2 +1,2 @@
1
- export { default as FilePicker } from './FilePicker.vue';
2
- export type { FilePickerValue } from './FilePicker.vue';
1
+ export { default as FilePicker } from './index.vue';
2
+ export type { FilePickerValue, FilePickerModelValue } from './types';