@speckle/ui-components 2.16.1-alpha7 → 2.16.1-alpha8
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/AvatarEditor-1bbae637.js +193 -0
- package/dist/AvatarEditor-1bbae637.js.map +1 -0
- package/dist/AvatarEditor-f4b16291.cjs +2 -0
- package/dist/AvatarEditor-f4b16291.cjs.map +1 -0
- package/dist/components/common/loading/Icon.vue.d.ts +24 -0
- package/dist/components/form/file-upload/Zone.vue.d.ts +62 -0
- package/dist/components/user/Avatar.vue.d.ts +58 -0
- package/dist/components/user/AvatarEditable.vue.d.ts +21 -0
- package/dist/components/user/AvatarEditor.vue.d.ts +26 -0
- package/dist/components/user/AvatarGroup.vue.d.ts +44 -0
- package/dist/composables/form/fileUpload.d.ts +63 -0
- package/dist/composables/user/avatar.d.ts +19 -0
- package/dist/helpers/common/error.d.ts +28 -0
- package/dist/helpers/form/file.d.ts +41 -0
- package/dist/lib.cjs +1 -1
- package/dist/lib.cjs.map +1 -1
- package/dist/lib.d.ts +10 -2
- package/dist/lib.js +1935 -1479
- package/dist/lib.js.map +1 -1
- package/dist/stories/helpers/avatar.d.ts +1 -0
- package/package.json +2 -1
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { defineComponent as j, ref as d, onUnmounted as N, watch as x, openBlock as g, createElementBlock as V, createElementVNode as a, normalizeClass as f, withDirectives as c, createVNode as r, unref as t, createBlock as O, createCommentVNode as S, withCtx as m, mergeProps as D, toHandlers as E, createTextVNode as k } from "vue";
|
|
2
|
+
import { ArrowUturnLeftIcon as P, ArrowUturnRightIcon as Z, ArrowUpOnSquareIcon as $, ArrowLeftOnRectangleIcon as H, PhotoIcon as q, XMarkIcon as M } from "@heroicons/vue/24/outline";
|
|
3
|
+
import { Cropper as T } from "vue-advanced-cropper";
|
|
4
|
+
import "vue-advanced-cropper/dist/style.css";
|
|
5
|
+
import { FormButton as i, FormFileUploadZone as X } from "./lib.js";
|
|
6
|
+
import { directive as s } from "vue-tippy";
|
|
7
|
+
import "lodash";
|
|
8
|
+
import "@heroicons/vue/24/solid";
|
|
9
|
+
import "@heroicons/vue/20/solid";
|
|
10
|
+
import "vee-validate";
|
|
11
|
+
import "nanoid";
|
|
12
|
+
import "@speckle/shared";
|
|
13
|
+
import "@vueuse/core";
|
|
14
|
+
import "@headlessui/vue";
|
|
15
|
+
import "v3-infinite-loading";
|
|
16
|
+
const G = { class: "flex flex-col space-y-2" }, J = { class: "flex" }, K = { class: "flex mx-14 space-x-2" }, Q = /* @__PURE__ */ a("div", { class: "grow" }, null, -1), me = /* @__PURE__ */ j({
|
|
17
|
+
__name: "AvatarEditor",
|
|
18
|
+
props: {
|
|
19
|
+
user: null,
|
|
20
|
+
disabled: { type: Boolean }
|
|
21
|
+
},
|
|
22
|
+
emits: ["cancel", "save"],
|
|
23
|
+
setup(p, { emit: C }) {
|
|
24
|
+
const R = p, n = d(
|
|
25
|
+
null
|
|
26
|
+
), v = d(null), u = d(null), l = d(null), _ = (e) => {
|
|
27
|
+
l.value && URL.revokeObjectURL(l.value), l.value = e;
|
|
28
|
+
}, y = (e) => {
|
|
29
|
+
const o = e.files[0];
|
|
30
|
+
o && (u.value = o);
|
|
31
|
+
}, b = (e) => {
|
|
32
|
+
var o;
|
|
33
|
+
return e ? "border-primary" : (o = u.value) != null && o.error ? "border-danger" : "border-outline-2";
|
|
34
|
+
}, z = () => {
|
|
35
|
+
var e;
|
|
36
|
+
return (e = n.value) == null ? void 0 : e.rotate(-90);
|
|
37
|
+
}, L = () => {
|
|
38
|
+
var e;
|
|
39
|
+
return (e = n.value) == null ? void 0 : e.rotate(90);
|
|
40
|
+
}, U = () => {
|
|
41
|
+
var e;
|
|
42
|
+
return (e = n.value) == null ? void 0 : e.flip(1, 0);
|
|
43
|
+
}, w = () => {
|
|
44
|
+
var e;
|
|
45
|
+
return (e = n.value) == null ? void 0 : e.flip(0, 1);
|
|
46
|
+
}, I = () => {
|
|
47
|
+
var e;
|
|
48
|
+
return (e = v.value) == null ? void 0 : e.triggerPicker();
|
|
49
|
+
}, A = () => {
|
|
50
|
+
u.value = null, l.value = null;
|
|
51
|
+
}, B = () => {
|
|
52
|
+
var o;
|
|
53
|
+
const e = ((o = n.value) == null ? void 0 : o.getResult().canvas.toDataURL("image/jpeg", 0.85)) || null;
|
|
54
|
+
C("save", e);
|
|
55
|
+
};
|
|
56
|
+
return N(() => {
|
|
57
|
+
_(null);
|
|
58
|
+
}), x(
|
|
59
|
+
() => R.user.avatar,
|
|
60
|
+
(e) => {
|
|
61
|
+
l.value = e || null;
|
|
62
|
+
},
|
|
63
|
+
{ immediate: !0 }
|
|
64
|
+
), x(
|
|
65
|
+
u,
|
|
66
|
+
(e) => {
|
|
67
|
+
l.value = e != null && e.file && !e.error ? URL.createObjectURL(e.file) : null;
|
|
68
|
+
},
|
|
69
|
+
{ deep: !0 }
|
|
70
|
+
), (e, o) => (g(), V("div", G, [
|
|
71
|
+
a("div", J, [
|
|
72
|
+
a("div", {
|
|
73
|
+
class: f(["flex flex-col px-2 space-y-1", { invisible: !l.value }])
|
|
74
|
+
}, [
|
|
75
|
+
c(r(i, {
|
|
76
|
+
"icon-left": t(P),
|
|
77
|
+
"hide-text": "",
|
|
78
|
+
size: "sm",
|
|
79
|
+
outlined: "",
|
|
80
|
+
onClick: z
|
|
81
|
+
}, null, 8, ["icon-left"]), [
|
|
82
|
+
[t(s), "Rotate left"]
|
|
83
|
+
]),
|
|
84
|
+
c(r(i, {
|
|
85
|
+
"icon-left": t(Z),
|
|
86
|
+
"hide-text": "",
|
|
87
|
+
size: "sm",
|
|
88
|
+
outlined: "",
|
|
89
|
+
onClick: L
|
|
90
|
+
}, null, 8, ["icon-left"]), [
|
|
91
|
+
[t(s), "Rotate right"]
|
|
92
|
+
]),
|
|
93
|
+
c(r(i, {
|
|
94
|
+
"icon-left": t($),
|
|
95
|
+
"hide-text": "",
|
|
96
|
+
size: "sm",
|
|
97
|
+
outlined: "",
|
|
98
|
+
onClick: w
|
|
99
|
+
}, null, 8, ["icon-left"]), [
|
|
100
|
+
[t(s), "Flip vertically"]
|
|
101
|
+
]),
|
|
102
|
+
c(r(i, {
|
|
103
|
+
"icon-left": t(H),
|
|
104
|
+
"hide-text": "",
|
|
105
|
+
size: "sm",
|
|
106
|
+
outlined: "",
|
|
107
|
+
onClick: U
|
|
108
|
+
}, null, 8, ["icon-left"]), [
|
|
109
|
+
[t(s), "Flip horizontally"]
|
|
110
|
+
])
|
|
111
|
+
], 2),
|
|
112
|
+
l.value ? (g(), O(t(T), {
|
|
113
|
+
key: 0,
|
|
114
|
+
ref_key: "cropper",
|
|
115
|
+
ref: n,
|
|
116
|
+
class: "cropper",
|
|
117
|
+
src: l.value,
|
|
118
|
+
"stencil-props": {
|
|
119
|
+
aspectRatio: 1 / 1
|
|
120
|
+
},
|
|
121
|
+
canvas: {
|
|
122
|
+
width: 250,
|
|
123
|
+
height: 250
|
|
124
|
+
},
|
|
125
|
+
style: { width: "250px", height: "250px" }
|
|
126
|
+
}, null, 8, ["src"])) : S("", !0),
|
|
127
|
+
r(X, {
|
|
128
|
+
ref_key: "uploadZone",
|
|
129
|
+
ref: v,
|
|
130
|
+
class: f(["cropper flex items-center justify-center", { hidden: l.value }]),
|
|
131
|
+
accept: "image/*",
|
|
132
|
+
"size-limit": 5 * 1024 * 1024,
|
|
133
|
+
onFilesSelected: y
|
|
134
|
+
}, {
|
|
135
|
+
default: m(({ isDraggingFiles: h, activatorOn: F }) => [
|
|
136
|
+
a("div", D({
|
|
137
|
+
class: ["cursor-pointer text-center w-full h-full border-dashed border-2 rounded-md p-4 flex items-center justify-center text-sm text-foreground-2", [b(h)]]
|
|
138
|
+
}, E(F, !0)), " Click here or drag and drop an image ", 16)
|
|
139
|
+
]),
|
|
140
|
+
_: 1
|
|
141
|
+
}, 8, ["class"]),
|
|
142
|
+
a("div", {
|
|
143
|
+
class: f(["flex flex-col px-2 space-y-1", { invisible: !l.value }])
|
|
144
|
+
}, [
|
|
145
|
+
c(r(i, {
|
|
146
|
+
"icon-left": t(q),
|
|
147
|
+
"hide-text": "",
|
|
148
|
+
size: "sm",
|
|
149
|
+
onClick: I
|
|
150
|
+
}, null, 8, ["icon-left"]), [
|
|
151
|
+
[t(s), "Replace image"]
|
|
152
|
+
]),
|
|
153
|
+
c(r(i, {
|
|
154
|
+
"icon-left": t(M),
|
|
155
|
+
"hide-text": "",
|
|
156
|
+
size: "sm",
|
|
157
|
+
color: "danger",
|
|
158
|
+
onClick: A
|
|
159
|
+
}, null, 8, ["icon-left"]), [
|
|
160
|
+
[t(s), "Remove"]
|
|
161
|
+
])
|
|
162
|
+
], 2)
|
|
163
|
+
]),
|
|
164
|
+
a("div", K, [
|
|
165
|
+
Q,
|
|
166
|
+
r(i, {
|
|
167
|
+
color: "secondary",
|
|
168
|
+
size: "sm",
|
|
169
|
+
onClick: o[0] || (o[0] = (h) => e.$emit("cancel"))
|
|
170
|
+
}, {
|
|
171
|
+
default: m(() => [
|
|
172
|
+
k(" Cancel ")
|
|
173
|
+
]),
|
|
174
|
+
_: 1
|
|
175
|
+
}),
|
|
176
|
+
r(i, {
|
|
177
|
+
size: "sm",
|
|
178
|
+
disabled: p.disabled,
|
|
179
|
+
onClick: B
|
|
180
|
+
}, {
|
|
181
|
+
default: m(() => [
|
|
182
|
+
k("Save")
|
|
183
|
+
]),
|
|
184
|
+
_: 1
|
|
185
|
+
}, 8, ["disabled"])
|
|
186
|
+
])
|
|
187
|
+
]));
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
export {
|
|
191
|
+
me as default
|
|
192
|
+
};
|
|
193
|
+
//# sourceMappingURL=AvatarEditor-1bbae637.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AvatarEditor-1bbae637.js","sources":["../src/components/user/AvatarEditor.vue"],"sourcesContent":["<template>\n <div class=\"flex flex-col space-y-2\">\n <div class=\"flex\">\n <div class=\"flex flex-col px-2 space-y-1\" :class=\"{ invisible: !activeImageUrl }\">\n <FormButton\n v-tippy=\"'Rotate left'\"\n :icon-left=\"ArrowUturnLeftIcon\"\n hide-text\n size=\"sm\"\n outlined\n @click=\"rotateLeft\"\n />\n <FormButton\n v-tippy=\"'Rotate right'\"\n :icon-left=\"ArrowUturnRightIcon\"\n hide-text\n size=\"sm\"\n outlined\n @click=\"rotateRight\"\n />\n <FormButton\n v-tippy=\"'Flip vertically'\"\n :icon-left=\"ArrowUpOnSquareIcon\"\n hide-text\n size=\"sm\"\n outlined\n @click=\"flipVertical\"\n />\n <FormButton\n v-tippy=\"'Flip horizontally'\"\n :icon-left=\"ArrowLeftOnRectangleIcon\"\n hide-text\n size=\"sm\"\n outlined\n @click=\"flipHorizontal\"\n />\n </div>\n <Cropper\n v-if=\"activeImageUrl\"\n ref=\"cropper\"\n class=\"cropper\"\n :src=\"activeImageUrl\"\n :stencil-props=\"{\n aspectRatio: 1 / 1\n }\"\n :canvas=\"{\n width: 250,\n height: 250\n }\"\n style=\"width: 250px; height: 250px\"\n />\n <FormFileUploadZone\n ref=\"uploadZone\"\n v-slot=\"{ isDraggingFiles, activatorOn }\"\n class=\"cropper flex items-center justify-center\"\n :class=\"{ hidden: activeImageUrl }\"\n accept=\"image/*\"\n :size-limit=\"5 * 1024 * 1024\"\n @files-selected=\"onFilesSelected\"\n >\n <div\n class=\"cursor-pointer text-center w-full h-full border-dashed border-2 rounded-md p-4 flex items-center justify-center text-sm text-foreground-2\"\n :class=\"[getDashedBorderClasses(isDraggingFiles)]\"\n v-on=\"activatorOn\"\n >\n Click here or drag and drop an image\n </div>\n </FormFileUploadZone>\n <div class=\"flex flex-col px-2 space-y-1\" :class=\"{ invisible: !activeImageUrl }\">\n <FormButton\n v-tippy=\"'Replace image'\"\n :icon-left=\"PhotoIcon\"\n hide-text\n size=\"sm\"\n @click=\"onReplace\"\n />\n <FormButton\n v-tippy=\"'Remove'\"\n :icon-left=\"XMarkIcon\"\n hide-text\n size=\"sm\"\n color=\"danger\"\n @click=\"onRemove\"\n />\n </div>\n </div>\n <div class=\"flex mx-14 space-x-2\">\n <div class=\"grow\" />\n <FormButton color=\"secondary\" size=\"sm\" @click=\"$emit('cancel')\">\n Cancel\n </FormButton>\n <FormButton size=\"sm\" :disabled=\"disabled\" @click=\"onSave\">Save</FormButton>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n ArrowUturnLeftIcon,\n ArrowUturnRightIcon,\n ArrowLeftOnRectangleIcon,\n ArrowUpOnSquareIcon,\n XMarkIcon,\n PhotoIcon\n} from '@heroicons/vue/24/outline'\nimport { Nullable } from '@speckle/shared'\nimport { onUnmounted, ref, watch } from 'vue'\nimport { Cropper } from 'vue-advanced-cropper'\nimport 'vue-advanced-cropper/dist/style.css'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport FormFileUploadZone from '~~/src/components/form/file-upload/Zone.vue'\nimport { UploadableFileItem } from '~~/src/composables/form/fileUpload'\nimport { AvatarUser } from '~~/src/composables/user/avatar'\nimport { directive as vTippy } from 'vue-tippy'\n\n/**\n * Always try to lazy load this, as it's quite heavy\n */\n\nconst emit = defineEmits([\"cancel\", \"save\"])\n\nconst props = defineProps({\n \"user\": null,\n \"disabled\": { type: Boolean, }\n})\n\nconst cropper = ref(\n null as Nullable<{\n flip: (x: number, y: number) => void\n rotate: (angle: number) => void\n getResult: () => { canvas: HTMLCanvasElement }\n }>\n)\nconst uploadZone = ref(null as Nullable<{ triggerPicker: () => void }>)\nconst selectedUpload = ref(null as Nullable<UploadableFileItem>)\nconst activeImageUrl = ref(null as Nullable<string>)\n\nconst setNewActiveUrl = (url: Nullable<string>) => {\n if (activeImageUrl.value) {\n URL.revokeObjectURL(activeImageUrl.value)\n }\n\n activeImageUrl.value = url\n}\n\nconst onFilesSelected = (params: { files: UploadableFileItem[] }) => {\n const file = params.files[0]\n if (!file) return\n selectedUpload.value = file\n}\n\nconst getDashedBorderClasses = (isDraggingFiles: boolean) => {\n if (isDraggingFiles) return 'border-primary'\n if (selectedUpload.value?.error) return 'border-danger'\n\n return 'border-outline-2'\n}\n\nconst rotateLeft = () => cropper.value?.rotate(-90)\nconst rotateRight = () => cropper.value?.rotate(90)\nconst flipHorizontal = () => cropper.value?.flip(1, 0)\nconst flipVertical = () => cropper.value?.flip(0, 1)\n\nconst onReplace = () => uploadZone.value?.triggerPicker()\nconst onRemove = () => {\n selectedUpload.value = null\n activeImageUrl.value = null\n}\nconst onSave = () => {\n const newUrl = cropper.value?.getResult().canvas.toDataURL('image/jpeg', 0.85) || null\n emit('save', newUrl)\n}\n\nonUnmounted(() => {\n setNewActiveUrl(null)\n})\n\nwatch(\n () => props.user.avatar,\n (newAvatar) => {\n activeImageUrl.value = newAvatar || null\n },\n { immediate: true }\n)\n\nwatch(\n selectedUpload,\n (newUpload) => {\n activeImageUrl.value =\n newUpload?.file && !newUpload.error ? URL.createObjectURL(newUpload.file) : null\n },\n { deep: true }\n)\n</script>\n"],"names":["cropper","ref","uploadZone","selectedUpload","activeImageUrl","setNewActiveUrl","url","onFilesSelected","params","file","getDashedBorderClasses","isDraggingFiles","_a","rotateLeft","rotateRight","flipHorizontal","flipVertical","onReplace","onRemove","onSave","newUrl","emit","onUnmounted","watch","props","newAvatar","newUpload"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;iBA6HMA,IAAUC;AAAA,MACd;AAAA,IAAA,GAMIC,IAAaD,EAAI,IAA+C,GAChEE,IAAiBF,EAAI,IAAoC,GACzDG,IAAiBH,EAAI,IAAwB,GAE7CI,IAAkB,CAACC,MAA0B;AACjD,MAAIF,EAAe,SACb,IAAA,gBAAgBA,EAAe,KAAK,GAG1CA,EAAe,QAAQE;AAAA,IAAA,GAGnBC,IAAkB,CAACC,MAA4C;AAC7D,YAAAC,IAAOD,EAAO,MAAM,CAAC;AAC3B,MAAKC,MACLN,EAAe,QAAQM;AAAA,IAAA,GAGnBC,IAAyB,CAACC,MAA6B;;AACvD,aAAAA,IAAwB,oBACxBC,IAAAT,EAAe,UAAf,QAAAS,EAAsB,QAAc,kBAEjC;AAAA,IAAA,GAGHC,IAAa,MAAA;;AAAM,cAAAD,IAAAZ,EAAQ,UAAR,gBAAAY,EAAe,OAAO;AAAA,OACzCE,IAAc,MAAA;;AAAM,cAAAF,IAAAZ,EAAQ,UAAR,gBAAAY,EAAe,OAAO;AAAA,OAC1CG,IAAiB,MAAA;;AAAM,cAAAH,IAAAZ,EAAQ,UAAR,gBAAAY,EAAe,KAAK,GAAG;AAAA,OAC9CI,IAAe,MAAA;;AAAM,cAAAJ,IAAAZ,EAAQ,UAAR,gBAAAY,EAAe,KAAK,GAAG;AAAA,OAE5CK,IAAY,MAAM;;AAAA,cAAAL,IAAAV,EAAW,UAAX,gBAAAU,EAAkB;AAAA,OACpCM,IAAW,MAAM;AACrB,MAAAf,EAAe,QAAQ,MACvBC,EAAe,QAAQ;AAAA,IAAA,GAEnBe,IAAS,MAAM;;AACb,YAAAC,MAASR,IAAAZ,EAAQ,UAAR,gBAAAY,EAAe,YAAY,OAAO,UAAU,cAAc,UAAS;AAClF,MAAAS,EAAK,QAAQD,CAAM;AAAA,IAAA;AAGrB,WAAAE,EAAY,MAAM;AAChB,MAAAjB,EAAgB,IAAI;AAAA,IAAA,CACrB,GAEDkB;AAAA,MACE,MAAMC,EAAM,KAAK;AAAA,MACjB,CAACC,MAAc;AACb,QAAArB,EAAe,QAAQqB,KAAa;AAAA,MACtC;AAAA,MACA,EAAE,WAAW,GAAK;AAAA,IAAA,GAGpBF;AAAA,MACEpB;AAAA,MACA,CAACuB,MAAc;AACE,QAAAtB,EAAA,QACbsB,KAAA,QAAAA,EAAW,QAAQ,CAACA,EAAU,QAAQ,IAAI,gBAAgBA,EAAU,IAAI,IAAI;AAAA,MAChF;AAAA,MACA,EAAE,MAAM,GAAK;AAAA,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),n=require("@heroicons/vue/24/outline"),q=require("vue-advanced-cropper");require("vue-advanced-cropper/dist/style.css");const o=require("./lib.cjs"),c=require("vue-tippy");require("lodash");require("@heroicons/vue/24/solid");require("@heroicons/vue/20/solid");require("vee-validate");require("nanoid");require("@speckle/shared");require("@vueuse/core");require("@headlessui/vue");require("v3-infinite-loading");const R={class:"flex flex-col space-y-2"},w={class:"flex"},z={class:"flex mx-14 space-x-2"},B=e.createElementVNode("div",{class:"grow"},null,-1),_=e.defineComponent({__name:"AvatarEditor",props:{user:null,disabled:{type:Boolean}},emits:["cancel","save"],setup(s,{emit:f}){const v=s,i=e.ref(null),u=e.ref(null),a=e.ref(null),r=e.ref(null),m=t=>{r.value&&URL.revokeObjectURL(r.value),r.value=t},p=t=>{const l=t.files[0];l&&(a.value=l)},h=t=>{var l;return t?"border-primary":(l=a.value)!=null&&l.error?"border-danger":"border-outline-2"},x=()=>{var t;return(t=i.value)==null?void 0:t.rotate(-90)},g=()=>{var t;return(t=i.value)==null?void 0:t.rotate(90)},C=()=>{var t;return(t=i.value)==null?void 0:t.flip(1,0)},k=()=>{var t;return(t=i.value)==null?void 0:t.flip(0,1)},N=()=>{var t;return(t=u.value)==null?void 0:t.triggerPicker()},V=()=>{a.value=null,r.value=null},y=()=>{var l;const t=((l=i.value)==null?void 0:l.getResult().canvas.toDataURL("image/jpeg",.85))||null;f("save",t)};return e.onUnmounted(()=>{m(null)}),e.watch(()=>v.user.avatar,t=>{r.value=t||null},{immediate:!0}),e.watch(a,t=>{r.value=t!=null&&t.file&&!t.error?URL.createObjectURL(t.file):null},{deep:!0}),(t,l)=>(e.openBlock(),e.createElementBlock("div",R,[e.createElementVNode("div",w,[e.createElementVNode("div",{class:e.normalizeClass(["flex flex-col px-2 space-y-1",{invisible:!r.value}])},[e.withDirectives(e.createVNode(o.FormButton,{"icon-left":e.unref(n.ArrowUturnLeftIcon),"hide-text":"",size:"sm",outlined:"",onClick:x},null,8,["icon-left"]),[[e.unref(c.directive),"Rotate left"]]),e.withDirectives(e.createVNode(o.FormButton,{"icon-left":e.unref(n.ArrowUturnRightIcon),"hide-text":"",size:"sm",outlined:"",onClick:g},null,8,["icon-left"]),[[e.unref(c.directive),"Rotate right"]]),e.withDirectives(e.createVNode(o.FormButton,{"icon-left":e.unref(n.ArrowUpOnSquareIcon),"hide-text":"",size:"sm",outlined:"",onClick:k},null,8,["icon-left"]),[[e.unref(c.directive),"Flip vertically"]]),e.withDirectives(e.createVNode(o.FormButton,{"icon-left":e.unref(n.ArrowLeftOnRectangleIcon),"hide-text":"",size:"sm",outlined:"",onClick:C},null,8,["icon-left"]),[[e.unref(c.directive),"Flip horizontally"]])],2),r.value?(e.openBlock(),e.createBlock(e.unref(q.Cropper),{key:0,ref_key:"cropper",ref:i,class:"cropper",src:r.value,"stencil-props":{aspectRatio:1/1},canvas:{width:250,height:250},style:{width:"250px",height:"250px"}},null,8,["src"])):e.createCommentVNode("",!0),e.createVNode(o.FormFileUploadZone,{ref_key:"uploadZone",ref:u,class:e.normalizeClass(["cropper flex items-center justify-center",{hidden:r.value}]),accept:"image/*","size-limit":5*1024*1024,onFilesSelected:p},{default:e.withCtx(({isDraggingFiles:d,activatorOn:b})=>[e.createElementVNode("div",e.mergeProps({class:["cursor-pointer text-center w-full h-full border-dashed border-2 rounded-md p-4 flex items-center justify-center text-sm text-foreground-2",[h(d)]]},e.toHandlers(b,!0))," Click here or drag and drop an image ",16)]),_:1},8,["class"]),e.createElementVNode("div",{class:e.normalizeClass(["flex flex-col px-2 space-y-1",{invisible:!r.value}])},[e.withDirectives(e.createVNode(o.FormButton,{"icon-left":e.unref(n.PhotoIcon),"hide-text":"",size:"sm",onClick:N},null,8,["icon-left"]),[[e.unref(c.directive),"Replace image"]]),e.withDirectives(e.createVNode(o.FormButton,{"icon-left":e.unref(n.XMarkIcon),"hide-text":"",size:"sm",color:"danger",onClick:V},null,8,["icon-left"]),[[e.unref(c.directive),"Remove"]])],2)]),e.createElementVNode("div",z,[B,e.createVNode(o.FormButton,{color:"secondary",size:"sm",onClick:l[0]||(l[0]=d=>t.$emit("cancel"))},{default:e.withCtx(()=>[e.createTextVNode(" Cancel ")]),_:1}),e.createVNode(o.FormButton,{size:"sm",disabled:s.disabled,onClick:y},{default:e.withCtx(()=>[e.createTextVNode("Save")]),_:1},8,["disabled"])])]))}});exports.default=_;
|
|
2
|
+
//# sourceMappingURL=AvatarEditor-f4b16291.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AvatarEditor-f4b16291.cjs","sources":["../src/components/user/AvatarEditor.vue"],"sourcesContent":["<template>\n <div class=\"flex flex-col space-y-2\">\n <div class=\"flex\">\n <div class=\"flex flex-col px-2 space-y-1\" :class=\"{ invisible: !activeImageUrl }\">\n <FormButton\n v-tippy=\"'Rotate left'\"\n :icon-left=\"ArrowUturnLeftIcon\"\n hide-text\n size=\"sm\"\n outlined\n @click=\"rotateLeft\"\n />\n <FormButton\n v-tippy=\"'Rotate right'\"\n :icon-left=\"ArrowUturnRightIcon\"\n hide-text\n size=\"sm\"\n outlined\n @click=\"rotateRight\"\n />\n <FormButton\n v-tippy=\"'Flip vertically'\"\n :icon-left=\"ArrowUpOnSquareIcon\"\n hide-text\n size=\"sm\"\n outlined\n @click=\"flipVertical\"\n />\n <FormButton\n v-tippy=\"'Flip horizontally'\"\n :icon-left=\"ArrowLeftOnRectangleIcon\"\n hide-text\n size=\"sm\"\n outlined\n @click=\"flipHorizontal\"\n />\n </div>\n <Cropper\n v-if=\"activeImageUrl\"\n ref=\"cropper\"\n class=\"cropper\"\n :src=\"activeImageUrl\"\n :stencil-props=\"{\n aspectRatio: 1 / 1\n }\"\n :canvas=\"{\n width: 250,\n height: 250\n }\"\n style=\"width: 250px; height: 250px\"\n />\n <FormFileUploadZone\n ref=\"uploadZone\"\n v-slot=\"{ isDraggingFiles, activatorOn }\"\n class=\"cropper flex items-center justify-center\"\n :class=\"{ hidden: activeImageUrl }\"\n accept=\"image/*\"\n :size-limit=\"5 * 1024 * 1024\"\n @files-selected=\"onFilesSelected\"\n >\n <div\n class=\"cursor-pointer text-center w-full h-full border-dashed border-2 rounded-md p-4 flex items-center justify-center text-sm text-foreground-2\"\n :class=\"[getDashedBorderClasses(isDraggingFiles)]\"\n v-on=\"activatorOn\"\n >\n Click here or drag and drop an image\n </div>\n </FormFileUploadZone>\n <div class=\"flex flex-col px-2 space-y-1\" :class=\"{ invisible: !activeImageUrl }\">\n <FormButton\n v-tippy=\"'Replace image'\"\n :icon-left=\"PhotoIcon\"\n hide-text\n size=\"sm\"\n @click=\"onReplace\"\n />\n <FormButton\n v-tippy=\"'Remove'\"\n :icon-left=\"XMarkIcon\"\n hide-text\n size=\"sm\"\n color=\"danger\"\n @click=\"onRemove\"\n />\n </div>\n </div>\n <div class=\"flex mx-14 space-x-2\">\n <div class=\"grow\" />\n <FormButton color=\"secondary\" size=\"sm\" @click=\"$emit('cancel')\">\n Cancel\n </FormButton>\n <FormButton size=\"sm\" :disabled=\"disabled\" @click=\"onSave\">Save</FormButton>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n ArrowUturnLeftIcon,\n ArrowUturnRightIcon,\n ArrowLeftOnRectangleIcon,\n ArrowUpOnSquareIcon,\n XMarkIcon,\n PhotoIcon\n} from '@heroicons/vue/24/outline'\nimport { Nullable } from '@speckle/shared'\nimport { onUnmounted, ref, watch } from 'vue'\nimport { Cropper } from 'vue-advanced-cropper'\nimport 'vue-advanced-cropper/dist/style.css'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport FormFileUploadZone from '~~/src/components/form/file-upload/Zone.vue'\nimport { UploadableFileItem } from '~~/src/composables/form/fileUpload'\nimport { AvatarUser } from '~~/src/composables/user/avatar'\nimport { directive as vTippy } from 'vue-tippy'\n\n/**\n * Always try to lazy load this, as it's quite heavy\n */\n\nconst emit = defineEmits([\"cancel\", \"save\"])\n\nconst props = defineProps({\n \"user\": null,\n \"disabled\": { type: Boolean, }\n})\n\nconst cropper = ref(\n null as Nullable<{\n flip: (x: number, y: number) => void\n rotate: (angle: number) => void\n getResult: () => { canvas: HTMLCanvasElement }\n }>\n)\nconst uploadZone = ref(null as Nullable<{ triggerPicker: () => void }>)\nconst selectedUpload = ref(null as Nullable<UploadableFileItem>)\nconst activeImageUrl = ref(null as Nullable<string>)\n\nconst setNewActiveUrl = (url: Nullable<string>) => {\n if (activeImageUrl.value) {\n URL.revokeObjectURL(activeImageUrl.value)\n }\n\n activeImageUrl.value = url\n}\n\nconst onFilesSelected = (params: { files: UploadableFileItem[] }) => {\n const file = params.files[0]\n if (!file) return\n selectedUpload.value = file\n}\n\nconst getDashedBorderClasses = (isDraggingFiles: boolean) => {\n if (isDraggingFiles) return 'border-primary'\n if (selectedUpload.value?.error) return 'border-danger'\n\n return 'border-outline-2'\n}\n\nconst rotateLeft = () => cropper.value?.rotate(-90)\nconst rotateRight = () => cropper.value?.rotate(90)\nconst flipHorizontal = () => cropper.value?.flip(1, 0)\nconst flipVertical = () => cropper.value?.flip(0, 1)\n\nconst onReplace = () => uploadZone.value?.triggerPicker()\nconst onRemove = () => {\n selectedUpload.value = null\n activeImageUrl.value = null\n}\nconst onSave = () => {\n const newUrl = cropper.value?.getResult().canvas.toDataURL('image/jpeg', 0.85) || null\n emit('save', newUrl)\n}\n\nonUnmounted(() => {\n setNewActiveUrl(null)\n})\n\nwatch(\n () => props.user.avatar,\n (newAvatar) => {\n activeImageUrl.value = newAvatar || null\n },\n { immediate: true }\n)\n\nwatch(\n selectedUpload,\n (newUpload) => {\n activeImageUrl.value =\n newUpload?.file && !newUpload.error ? URL.createObjectURL(newUpload.file) : null\n },\n { deep: true }\n)\n</script>\n"],"names":["cropper","ref","uploadZone","selectedUpload","activeImageUrl","setNewActiveUrl","url","onFilesSelected","params","file","getDashedBorderClasses","isDraggingFiles","_a","rotateLeft","rotateRight","flipHorizontal","flipVertical","onReplace","onRemove","onSave","newUrl","emit","onUnmounted","watch","props","newAvatar","newUpload"],"mappings":"4xBA6HMA,EAAUC,EAAA,IACd,IAAA,EAMIC,EAAaD,MAAI,IAA+C,EAChEE,EAAiBF,MAAI,IAAoC,EACzDG,EAAiBH,MAAI,IAAwB,EAE7CI,EAAmBC,GAA0B,CAC7CF,EAAe,OACb,IAAA,gBAAgBA,EAAe,KAAK,EAG1CA,EAAe,MAAQE,CAAA,EAGnBC,EAAmBC,GAA4C,CAC7D,MAAAC,EAAOD,EAAO,MAAM,CAAC,EACtBC,IACLN,EAAe,MAAQM,EAAA,EAGnBC,EAA0BC,GAA6B,OACvD,OAAAA,EAAwB,kBACxBC,EAAAT,EAAe,QAAf,MAAAS,EAAsB,MAAc,gBAEjC,kBAAA,EAGHC,EAAa,IAAA,OAAM,OAAAD,EAAAZ,EAAQ,QAAR,YAAAY,EAAe,OAAO,MACzCE,EAAc,IAAA,OAAM,OAAAF,EAAAZ,EAAQ,QAAR,YAAAY,EAAe,OAAO,KAC1CG,EAAiB,IAAA,OAAM,OAAAH,EAAAZ,EAAQ,QAAR,YAAAY,EAAe,KAAK,EAAG,IAC9CI,EAAe,IAAA,OAAM,OAAAJ,EAAAZ,EAAQ,QAAR,YAAAY,EAAe,KAAK,EAAG,IAE5CK,EAAY,IAAM,OAAA,OAAAL,EAAAV,EAAW,QAAX,YAAAU,EAAkB,iBACpCM,EAAW,IAAM,CACrBf,EAAe,MAAQ,KACvBC,EAAe,MAAQ,IAAA,EAEnBe,EAAS,IAAM,OACb,MAAAC,IAASR,EAAAZ,EAAQ,QAAR,YAAAY,EAAe,YAAY,OAAO,UAAU,aAAc,OAAS,KAClFS,EAAK,OAAQD,CAAM,CAAA,EAGrBE,OAAAA,EAAAA,YAAY,IAAM,CAChBjB,EAAgB,IAAI,CAAA,CACrB,EAEDkB,EAAA,MACE,IAAMC,EAAM,KAAK,OAChBC,GAAc,CACbrB,EAAe,MAAQqB,GAAa,IACtC,EACA,CAAE,UAAW,EAAK,CAAA,EAGpBF,EAAA,MACEpB,EACCuB,GAAc,CACEtB,EAAA,MACbsB,GAAA,MAAAA,EAAW,MAAQ,CAACA,EAAU,MAAQ,IAAI,gBAAgBA,EAAU,IAAI,EAAI,IAChF,EACA,CAAE,KAAM,EAAK,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type Size = 'base' | 'sm' | 'lg';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<{
|
|
3
|
+
size: {
|
|
4
|
+
type: import("vue").PropType<Size>;
|
|
5
|
+
default: string;
|
|
6
|
+
};
|
|
7
|
+
loading: {
|
|
8
|
+
type: import("vue").PropType<boolean>;
|
|
9
|
+
default: boolean;
|
|
10
|
+
};
|
|
11
|
+
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
12
|
+
size: {
|
|
13
|
+
type: import("vue").PropType<Size>;
|
|
14
|
+
default: string;
|
|
15
|
+
};
|
|
16
|
+
loading: {
|
|
17
|
+
type: import("vue").PropType<boolean>;
|
|
18
|
+
default: boolean;
|
|
19
|
+
};
|
|
20
|
+
}>>, {
|
|
21
|
+
size: Size;
|
|
22
|
+
loading: boolean;
|
|
23
|
+
}, {}>;
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { UploadableFileItem } from '../../../composables/form/fileUpload';
|
|
2
|
+
declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
|
|
3
|
+
disabled: {
|
|
4
|
+
type: import("vue").PropType<boolean>;
|
|
5
|
+
};
|
|
6
|
+
accept: {
|
|
7
|
+
type: import("vue").PropType<string>;
|
|
8
|
+
};
|
|
9
|
+
multiple: {
|
|
10
|
+
type: import("vue").PropType<boolean>;
|
|
11
|
+
};
|
|
12
|
+
sizeLimit: {
|
|
13
|
+
type: import("vue").PropType<number>;
|
|
14
|
+
default: number;
|
|
15
|
+
};
|
|
16
|
+
countLimit: {
|
|
17
|
+
type: import("vue").PropType<number>;
|
|
18
|
+
};
|
|
19
|
+
}, {
|
|
20
|
+
triggerPicker: () => void;
|
|
21
|
+
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
22
|
+
"files-selected": (v: {
|
|
23
|
+
files: UploadableFileItem[];
|
|
24
|
+
}) => void;
|
|
25
|
+
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
26
|
+
disabled: {
|
|
27
|
+
type: import("vue").PropType<boolean>;
|
|
28
|
+
};
|
|
29
|
+
accept: {
|
|
30
|
+
type: import("vue").PropType<string>;
|
|
31
|
+
};
|
|
32
|
+
multiple: {
|
|
33
|
+
type: import("vue").PropType<boolean>;
|
|
34
|
+
};
|
|
35
|
+
sizeLimit: {
|
|
36
|
+
type: import("vue").PropType<number>;
|
|
37
|
+
default: number;
|
|
38
|
+
};
|
|
39
|
+
countLimit: {
|
|
40
|
+
type: import("vue").PropType<number>;
|
|
41
|
+
};
|
|
42
|
+
}>> & {
|
|
43
|
+
"onFiles-selected"?: ((v: {
|
|
44
|
+
files: UploadableFileItem[];
|
|
45
|
+
}) => any) | undefined;
|
|
46
|
+
}, {
|
|
47
|
+
sizeLimit: number;
|
|
48
|
+
}, {}>, {
|
|
49
|
+
default?(_: {
|
|
50
|
+
isDraggingFiles: boolean;
|
|
51
|
+
openFilePicker: () => void;
|
|
52
|
+
activatorOn: {
|
|
53
|
+
click: () => void;
|
|
54
|
+
};
|
|
55
|
+
}): any;
|
|
56
|
+
}>;
|
|
57
|
+
export default _default;
|
|
58
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
59
|
+
new (): {
|
|
60
|
+
$slots: S;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { AvatarUser, UserAvatarSize } from '../../composables/user/avatar';
|
|
2
|
+
declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
|
|
3
|
+
size: {
|
|
4
|
+
type: import("vue").PropType<UserAvatarSize>;
|
|
5
|
+
default: string;
|
|
6
|
+
};
|
|
7
|
+
active: {
|
|
8
|
+
type: import("vue").PropType<boolean>;
|
|
9
|
+
};
|
|
10
|
+
user: {
|
|
11
|
+
type: import("vue").PropType<AvatarUser | null>;
|
|
12
|
+
default: null;
|
|
13
|
+
};
|
|
14
|
+
hoverEffect: {
|
|
15
|
+
type: import("vue").PropType<boolean>;
|
|
16
|
+
default: boolean;
|
|
17
|
+
};
|
|
18
|
+
noBorder: {
|
|
19
|
+
type: import("vue").PropType<boolean>;
|
|
20
|
+
};
|
|
21
|
+
noBg: {
|
|
22
|
+
type: import("vue").PropType<boolean>;
|
|
23
|
+
};
|
|
24
|
+
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
25
|
+
size: {
|
|
26
|
+
type: import("vue").PropType<UserAvatarSize>;
|
|
27
|
+
default: string;
|
|
28
|
+
};
|
|
29
|
+
active: {
|
|
30
|
+
type: import("vue").PropType<boolean>;
|
|
31
|
+
};
|
|
32
|
+
user: {
|
|
33
|
+
type: import("vue").PropType<AvatarUser | null>;
|
|
34
|
+
default: null;
|
|
35
|
+
};
|
|
36
|
+
hoverEffect: {
|
|
37
|
+
type: import("vue").PropType<boolean>;
|
|
38
|
+
default: boolean;
|
|
39
|
+
};
|
|
40
|
+
noBorder: {
|
|
41
|
+
type: import("vue").PropType<boolean>;
|
|
42
|
+
};
|
|
43
|
+
noBg: {
|
|
44
|
+
type: import("vue").PropType<boolean>;
|
|
45
|
+
};
|
|
46
|
+
}>>, {
|
|
47
|
+
size: UserAvatarSize;
|
|
48
|
+
user: AvatarUser | null;
|
|
49
|
+
hoverEffect: boolean;
|
|
50
|
+
}, {}>, {
|
|
51
|
+
default?(_: {}): any;
|
|
52
|
+
}>;
|
|
53
|
+
export default _default;
|
|
54
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
55
|
+
new (): {
|
|
56
|
+
$slots: S;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Nullable } from '@speckle/shared';
|
|
2
|
+
import { AvatarUser } from '../../composables/user/avatar';
|
|
3
|
+
declare const _default: import("vue").DefineComponent<{
|
|
4
|
+
user: {
|
|
5
|
+
type: import("vue").PropType<AvatarUser>;
|
|
6
|
+
required: true;
|
|
7
|
+
};
|
|
8
|
+
}, {
|
|
9
|
+
open: () => boolean;
|
|
10
|
+
close: () => boolean;
|
|
11
|
+
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
save: (newUrl: Nullable<string>) => void;
|
|
13
|
+
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
14
|
+
user: {
|
|
15
|
+
type: import("vue").PropType<AvatarUser>;
|
|
16
|
+
required: true;
|
|
17
|
+
};
|
|
18
|
+
}>> & {
|
|
19
|
+
onSave?: ((newUrl: Nullable<string>) => any) | undefined;
|
|
20
|
+
}, {}, {}>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Nullable } from '@speckle/shared';
|
|
2
|
+
import { AvatarUser } from '../../composables/user/avatar';
|
|
3
|
+
declare const _default: import("vue").DefineComponent<{
|
|
4
|
+
user: {
|
|
5
|
+
type: import("vue").PropType<AvatarUser>;
|
|
6
|
+
required: true;
|
|
7
|
+
};
|
|
8
|
+
disabled: {
|
|
9
|
+
type: import("vue").PropType<boolean>;
|
|
10
|
+
};
|
|
11
|
+
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
cancel: () => void;
|
|
13
|
+
save: (val: Nullable<string>) => void;
|
|
14
|
+
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
15
|
+
user: {
|
|
16
|
+
type: import("vue").PropType<AvatarUser>;
|
|
17
|
+
required: true;
|
|
18
|
+
};
|
|
19
|
+
disabled: {
|
|
20
|
+
type: import("vue").PropType<boolean>;
|
|
21
|
+
};
|
|
22
|
+
}>> & {
|
|
23
|
+
onCancel?: (() => any) | undefined;
|
|
24
|
+
onSave?: ((val: Nullable<string>) => any) | undefined;
|
|
25
|
+
}, {}, {}>;
|
|
26
|
+
export default _default;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { UserAvatarSize, AvatarUserWithId } from '../../composables/user/avatar';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<{
|
|
3
|
+
size: {
|
|
4
|
+
type: import("vue").PropType<UserAvatarSize>;
|
|
5
|
+
default: string;
|
|
6
|
+
};
|
|
7
|
+
users: {
|
|
8
|
+
type: import("vue").PropType<AvatarUserWithId[]>;
|
|
9
|
+
required: true;
|
|
10
|
+
default: () => never[];
|
|
11
|
+
};
|
|
12
|
+
overlap: {
|
|
13
|
+
type: import("vue").PropType<boolean>;
|
|
14
|
+
default: boolean;
|
|
15
|
+
};
|
|
16
|
+
maxCount: {
|
|
17
|
+
type: import("vue").PropType<number>;
|
|
18
|
+
default: undefined;
|
|
19
|
+
};
|
|
20
|
+
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
21
|
+
size: {
|
|
22
|
+
type: import("vue").PropType<UserAvatarSize>;
|
|
23
|
+
default: string;
|
|
24
|
+
};
|
|
25
|
+
users: {
|
|
26
|
+
type: import("vue").PropType<AvatarUserWithId[]>;
|
|
27
|
+
required: true;
|
|
28
|
+
default: () => never[];
|
|
29
|
+
};
|
|
30
|
+
overlap: {
|
|
31
|
+
type: import("vue").PropType<boolean>;
|
|
32
|
+
default: boolean;
|
|
33
|
+
};
|
|
34
|
+
maxCount: {
|
|
35
|
+
type: import("vue").PropType<number>;
|
|
36
|
+
default: undefined;
|
|
37
|
+
};
|
|
38
|
+
}>>, {
|
|
39
|
+
size: UserAvatarSize;
|
|
40
|
+
users: AvatarUserWithId[];
|
|
41
|
+
overlap: boolean;
|
|
42
|
+
maxCount: number;
|
|
43
|
+
}, {}>;
|
|
44
|
+
export default _default;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { MaybeRef } from '@vueuse/core';
|
|
2
|
+
import { MaybeNullOrUndefined, Nullable, Optional } from '@speckle/shared';
|
|
3
|
+
import { CSSProperties } from 'vue';
|
|
4
|
+
/**
|
|
5
|
+
* A file, as emitted out from FileUploadZone
|
|
6
|
+
*/
|
|
7
|
+
export interface UploadableFileItem {
|
|
8
|
+
file: File;
|
|
9
|
+
error: Nullable<Error>;
|
|
10
|
+
/**
|
|
11
|
+
* You can use this ID to check for File equality
|
|
12
|
+
*/
|
|
13
|
+
id: string;
|
|
14
|
+
}
|
|
15
|
+
export declare enum BlobUploadStatus {
|
|
16
|
+
Success = 1,
|
|
17
|
+
Failure = 2
|
|
18
|
+
}
|
|
19
|
+
export type BlobPostResultItem = {
|
|
20
|
+
blobId?: string;
|
|
21
|
+
fileName?: string;
|
|
22
|
+
fileSize?: number;
|
|
23
|
+
formKey: string;
|
|
24
|
+
/**
|
|
25
|
+
* Success = 1, Failure = 2
|
|
26
|
+
*/
|
|
27
|
+
uploadStatus: number;
|
|
28
|
+
uploadError: string;
|
|
29
|
+
};
|
|
30
|
+
export interface UploadFileItem extends UploadableFileItem {
|
|
31
|
+
/**
|
|
32
|
+
* Progress between 0 and 100
|
|
33
|
+
*/
|
|
34
|
+
progress: number;
|
|
35
|
+
/**
|
|
36
|
+
* When upload has finished this contains a BlobPostResultItem
|
|
37
|
+
*/
|
|
38
|
+
result: Optional<BlobPostResultItem>;
|
|
39
|
+
/**
|
|
40
|
+
* When a blob gets assigned to a resource, it should count as in use, and this will
|
|
41
|
+
* prevent it from being deleted as junk
|
|
42
|
+
*/
|
|
43
|
+
inUse?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare function usePrepareUploadableFiles(params: {
|
|
46
|
+
disabled?: MaybeRef<Optional<boolean>>;
|
|
47
|
+
accept?: MaybeRef<Optional<string>>;
|
|
48
|
+
multiple?: MaybeRef<Optional<boolean>>;
|
|
49
|
+
countLimit?: MaybeRef<Optional<number>>;
|
|
50
|
+
sizeLimit: MaybeRef<number>;
|
|
51
|
+
}): {
|
|
52
|
+
/**
|
|
53
|
+
* Validate incoming files and build UploadableFileItem structs out of them
|
|
54
|
+
*/
|
|
55
|
+
buildUploadableFiles: (files: File[]) => UploadableFileItem[] | undefined;
|
|
56
|
+
};
|
|
57
|
+
export declare function useFileUploadProgressCore(params: {
|
|
58
|
+
item: MaybeRef<MaybeNullOrUndefined<UploadFileItem>>;
|
|
59
|
+
}): {
|
|
60
|
+
errorMessage: import("vue").ComputedRef<string | null>;
|
|
61
|
+
progressBarClasses: import("vue").ComputedRef<string>;
|
|
62
|
+
progressBarStyle: import("vue").ComputedRef<CSSProperties>;
|
|
63
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ToRefs } from 'vue';
|
|
2
|
+
export type AvatarUser = {
|
|
3
|
+
name: string;
|
|
4
|
+
avatar?: string | null;
|
|
5
|
+
};
|
|
6
|
+
export type AvatarUserWithId = AvatarUser & {
|
|
7
|
+
id: string;
|
|
8
|
+
};
|
|
9
|
+
export type UserAvatarSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | 'editable';
|
|
10
|
+
export declare function useAvatarSizeClasses(params: {
|
|
11
|
+
props: ToRefs<{
|
|
12
|
+
size?: UserAvatarSize;
|
|
13
|
+
}>;
|
|
14
|
+
}): {
|
|
15
|
+
heightClasses: import("vue").ComputedRef<"h-6" | "h-10" | "h-14" | "h-8" | "h-5" | "h-60">;
|
|
16
|
+
widthClasses: import("vue").ComputedRef<"w-5" | "w-6" | "w-10" | "w-14" | "w-60" | "w-8">;
|
|
17
|
+
sizeClasses: import("vue").ComputedRef<string>;
|
|
18
|
+
iconClasses: import("vue").ComputedRef<"w-5 h-5" | "w-3 h-3" | "w-8 h-8" | "w-20 h-20" | "w-4 h-4">;
|
|
19
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base ObjectLoader error
|
|
3
|
+
*/
|
|
4
|
+
export declare abstract class BaseError extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* Default message if none is passed
|
|
7
|
+
*/
|
|
8
|
+
static defaultMessage: string;
|
|
9
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Throw these in execution branches that should never occur unless if there's a bug
|
|
13
|
+
*/
|
|
14
|
+
export declare class LogicError extends BaseError {
|
|
15
|
+
static defaultMessage: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class UninitializedResourceAccessError extends BaseError {
|
|
18
|
+
static defaultMessage: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class ComposableInvokedOutOfScopeError extends BaseError {
|
|
21
|
+
static defaultMessage: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Throw this when something that's only supported during CSR is invoked during SSR or vice versa
|
|
25
|
+
*/
|
|
26
|
+
export declare class UnsupportedEnvironmentError extends BaseError {
|
|
27
|
+
static defaultMessage: string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Nullable } from '@speckle/shared';
|
|
2
|
+
import { BaseError } from '../../helpers/common/error';
|
|
3
|
+
export type FileTypeSpecifier = UniqueFileTypeSpecifier | `.${string}`;
|
|
4
|
+
export declare enum UniqueFileTypeSpecifier {
|
|
5
|
+
AnyAudio = "audio/*",
|
|
6
|
+
AnyVideo = "video/*",
|
|
7
|
+
AnyImage = "image/*"
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Validate if file has the allowed type. While we could also test for MIME types
|
|
11
|
+
* not in UniqueFileTypeSpecifier, this function is meant to be equivalent to the
|
|
12
|
+
* 'accept' attribute, which only allows for extensions or UniqueFileTypeSpecifier
|
|
13
|
+
* values.
|
|
14
|
+
* @param file
|
|
15
|
+
* @param allowedTypes The file must have one of these types
|
|
16
|
+
* @returns True if valid, Error object if not
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateFileType(file: File, allowedTypes: FileTypeSpecifier[]): true | Error;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve file extension (with leading dot)
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveFileExtension(fileName: string): Nullable<FileTypeSpecifier>;
|
|
23
|
+
/**
|
|
24
|
+
* Check if string is a FileTypeSpecifier
|
|
25
|
+
*/
|
|
26
|
+
export declare function isFileTypeSpecifier(type: string): type is FileTypeSpecifier;
|
|
27
|
+
/**
|
|
28
|
+
* Create a human readable file size string from the numeric size in bytes
|
|
29
|
+
*/
|
|
30
|
+
export declare function prettyFileSize(sizeInBytes: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* Generate an ID that uniquely identifies a specific file. The same file
|
|
33
|
+
* will always have the same ID.
|
|
34
|
+
*/
|
|
35
|
+
export declare function generateFileId(file: File): string;
|
|
36
|
+
export declare class MissingFileExtensionError extends BaseError {
|
|
37
|
+
static defaultMessage: string;
|
|
38
|
+
}
|
|
39
|
+
export declare class ForbiddenFileTypeError extends BaseError {
|
|
40
|
+
static defaultMessage: string;
|
|
41
|
+
}
|