@speckle/ui-components 2.16.0 → 2.16.1-alpha10

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 (35) hide show
  1. package/dist/AvatarEditor-594c4e0d.js +193 -0
  2. package/dist/AvatarEditor-594c4e0d.js.map +1 -0
  3. package/dist/AvatarEditor-92ea4e16.cjs +2 -0
  4. package/dist/AvatarEditor-92ea4e16.cjs.map +1 -0
  5. package/dist/components/common/loading/Icon.vue.d.ts +24 -0
  6. package/dist/components/form/Switch.vue.d.ts +6 -0
  7. package/dist/components/form/Tags.vue.d.ts +147 -0
  8. package/dist/components/form/TextArea.vue.d.ts +6 -0
  9. package/dist/components/form/TextInput.vue.d.ts +1 -1
  10. package/dist/components/form/file-upload/Zone.vue.d.ts +62 -0
  11. package/dist/components/form/select/Badges.vue.d.ts +64 -0
  12. package/dist/components/form/select/Base.vue.d.ts +375 -333
  13. package/dist/components/form/select/SourceApps.vue.d.ts +13 -0
  14. package/dist/components/form/tags/ContextManager.vue.d.ts +16 -0
  15. package/dist/components/layout/Table.vue.d.ts +68 -0
  16. package/dist/components/user/Avatar.vue.d.ts +59 -0
  17. package/dist/components/user/AvatarEditable.vue.d.ts +67 -0
  18. package/dist/components/user/AvatarEditor.vue.d.ts +26 -0
  19. package/dist/components/user/AvatarGroup.vue.d.ts +44 -0
  20. package/dist/composables/form/fileUpload.d.ts +63 -0
  21. package/dist/composables/form/textInput.d.ts +9 -5
  22. package/dist/composables/user/avatar.d.ts +19 -0
  23. package/dist/helpers/common/error.d.ts +28 -0
  24. package/dist/helpers/common/validation.d.ts +2 -0
  25. package/dist/helpers/form/file.d.ts +41 -0
  26. package/dist/lib.cjs +2 -1
  27. package/dist/lib.cjs.map +1 -0
  28. package/dist/lib.d.ts +14 -2
  29. package/dist/lib.js +2191 -1206
  30. package/dist/lib.js.map +1 -0
  31. package/dist/stories/helpers/avatar.d.ts +1 -0
  32. package/package.json +3 -2
  33. package/tailwind.config.cjs +11 -0
  34. package/tsconfig.json +1 -1
  35. package/vite.config.ts +6 -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(" Close ")
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-594c4e0d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarEditor-594c4e0d.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 Close\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(a,{emit:f}){const v=a,i=e.ref(null),u=e.ref(null),s=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&&(s.value=l)},h=t=>{var l;return t?"border-primary":(l=s.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=()=>{s.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(s,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(" Close ")]),_:1}),e.createVNode(o.FormButton,{size:"sm",disabled:a.disabled,onClick:y},{default:e.withCtx(()=>[e.createTextVNode("Save")]),_:1},8,["disabled"])])]))}});exports.default=_;
2
+ //# sourceMappingURL=AvatarEditor-92ea4e16.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarEditor-92ea4e16.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 Close\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,6 @@
1
+ declare const _default: import("vue").DefineComponent<{
2
+ modelValue: import("vue").PropType<boolean>;
3
+ }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
4
+ modelValue: import("vue").PropType<boolean>;
5
+ }>>, {}, {}>;
6
+ export default _default;
@@ -0,0 +1,147 @@
1
+ import { InputColor } from '../../composables/form/textInput';
2
+ import { MaybeAsync } from '@speckle/shared';
3
+ type InputSize = 'sm' | 'base' | 'lg' | 'xl';
4
+ declare const _default: import("vue").DefineComponent<{
5
+ size: {
6
+ type: import("vue").PropType<InputSize>;
7
+ default: string;
8
+ };
9
+ color: {
10
+ type: import("vue").PropType<InputColor>;
11
+ default: string;
12
+ };
13
+ disabled: {
14
+ type: import("vue").PropType<boolean>;
15
+ };
16
+ placeholder: {
17
+ type: import("vue").PropType<string>;
18
+ };
19
+ label: {
20
+ type: import("vue").PropType<string>;
21
+ };
22
+ name: {
23
+ type: import("vue").PropType<string>;
24
+ required: true;
25
+ };
26
+ modelValue: {
27
+ type: import("vue").PropType<string[]>;
28
+ };
29
+ rules: {
30
+ type: import("vue").PropType<string | Record<string, unknown> | import("vee-validate").GenericValidateFunction<string[]> | import("vee-validate").GenericValidateFunction<string[]>[] | {
31
+ validate(value: string[], options: Record<string, any>): Promise<string[]>;
32
+ }>;
33
+ };
34
+ validateOnMount: {
35
+ type: import("vue").PropType<boolean>;
36
+ };
37
+ showRequired: {
38
+ type: import("vue").PropType<boolean>;
39
+ };
40
+ validateOnValueUpdate: {
41
+ type: import("vue").PropType<boolean>;
42
+ };
43
+ help: {
44
+ type: import("vue").PropType<string>;
45
+ };
46
+ showLabel: {
47
+ type: import("vue").PropType<boolean>;
48
+ };
49
+ autoFocus: {
50
+ type: import("vue").PropType<boolean>;
51
+ };
52
+ showClear: {
53
+ type: import("vue").PropType<boolean>;
54
+ };
55
+ useLabelInErrors: {
56
+ type: import("vue").PropType<boolean>;
57
+ default: boolean;
58
+ };
59
+ wrapperClasses: {
60
+ type: import("vue").PropType<string>;
61
+ };
62
+ getAutocompleteItems: {
63
+ type: import("vue").PropType<(query: string) => MaybeAsync<string[]>>;
64
+ };
65
+ }, {
66
+ resolveAutocompleteItems: () => Promise<void>;
67
+ }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
68
+ "update:modelValue": (val: string[]) => void;
69
+ change: (val: {
70
+ event?: Event | undefined;
71
+ value: string[];
72
+ }) => void;
73
+ clear: () => void;
74
+ }, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
75
+ size: {
76
+ type: import("vue").PropType<InputSize>;
77
+ default: string;
78
+ };
79
+ color: {
80
+ type: import("vue").PropType<InputColor>;
81
+ default: string;
82
+ };
83
+ disabled: {
84
+ type: import("vue").PropType<boolean>;
85
+ };
86
+ placeholder: {
87
+ type: import("vue").PropType<string>;
88
+ };
89
+ label: {
90
+ type: import("vue").PropType<string>;
91
+ };
92
+ name: {
93
+ type: import("vue").PropType<string>;
94
+ required: true;
95
+ };
96
+ modelValue: {
97
+ type: import("vue").PropType<string[]>;
98
+ };
99
+ rules: {
100
+ type: import("vue").PropType<string | Record<string, unknown> | import("vee-validate").GenericValidateFunction<string[]> | import("vee-validate").GenericValidateFunction<string[]>[] | {
101
+ validate(value: string[], options: Record<string, any>): Promise<string[]>;
102
+ }>;
103
+ };
104
+ validateOnMount: {
105
+ type: import("vue").PropType<boolean>;
106
+ };
107
+ showRequired: {
108
+ type: import("vue").PropType<boolean>;
109
+ };
110
+ validateOnValueUpdate: {
111
+ type: import("vue").PropType<boolean>;
112
+ };
113
+ help: {
114
+ type: import("vue").PropType<string>;
115
+ };
116
+ showLabel: {
117
+ type: import("vue").PropType<boolean>;
118
+ };
119
+ autoFocus: {
120
+ type: import("vue").PropType<boolean>;
121
+ };
122
+ showClear: {
123
+ type: import("vue").PropType<boolean>;
124
+ };
125
+ useLabelInErrors: {
126
+ type: import("vue").PropType<boolean>;
127
+ default: boolean;
128
+ };
129
+ wrapperClasses: {
130
+ type: import("vue").PropType<string>;
131
+ };
132
+ getAutocompleteItems: {
133
+ type: import("vue").PropType<(query: string) => MaybeAsync<string[]>>;
134
+ };
135
+ }>> & {
136
+ onChange?: ((val: {
137
+ event?: Event | undefined;
138
+ value: string[];
139
+ }) => any) | undefined;
140
+ "onUpdate:modelValue"?: ((val: string[]) => any) | undefined;
141
+ onClear?: (() => any) | undefined;
142
+ }, {
143
+ size: InputSize;
144
+ color: InputColor;
145
+ useLabelInErrors: boolean;
146
+ }, {}>;
147
+ export default _default;
@@ -54,6 +54,9 @@ declare const _default: import("vue").DefineComponent<{
54
54
  type: import("vue").PropType<boolean>;
55
55
  default: boolean;
56
56
  };
57
+ textareaClasses: {
58
+ type: import("vue").PropType<string>;
59
+ };
57
60
  }, {
58
61
  focus: () => void;
59
62
  }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
@@ -122,6 +125,9 @@ declare const _default: import("vue").DefineComponent<{
122
125
  type: import("vue").PropType<boolean>;
123
126
  default: boolean;
124
127
  };
128
+ textareaClasses: {
129
+ type: import("vue").PropType<string>;
130
+ };
125
131
  }>> & {
126
132
  onChange?: ((val: {
127
133
  event?: Event | undefined;
@@ -313,8 +313,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
313
313
  showClear: boolean;
314
314
  useLabelInErrors: boolean;
315
315
  hideErrorMessage: boolean;
316
- inputClasses: string;
317
316
  wrapperClasses: string;
317
+ inputClasses: string;
318
318
  }, {}>, {
319
319
  "input-right"?(_: {}): any;
320
320
  }>;
@@ -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,64 @@
1
+ declare const _default: import("vue").DefineComponent<{
2
+ items: {
3
+ type: import("vue").PropType<any[]>;
4
+ required: true;
5
+ };
6
+ label: {
7
+ type: import("vue").PropType<string>;
8
+ required: true;
9
+ };
10
+ name: {
11
+ type: import("vue").PropType<string>;
12
+ required: true;
13
+ };
14
+ help: {
15
+ type: import("vue").PropType<string>;
16
+ };
17
+ modelValue: {
18
+ type: import("vue").PropType<any>;
19
+ };
20
+ multiple: {
21
+ type: import("vue").PropType<boolean>;
22
+ };
23
+ rules: {
24
+ type: import("vue").PropType<any[]>;
25
+ };
26
+ by: {
27
+ type: import("vue").PropType<string>;
28
+ required: true;
29
+ };
30
+ }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
+ "update:modelValue": (val: any[]) => void;
32
+ }, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
33
+ items: {
34
+ type: import("vue").PropType<any[]>;
35
+ required: true;
36
+ };
37
+ label: {
38
+ type: import("vue").PropType<string>;
39
+ required: true;
40
+ };
41
+ name: {
42
+ type: import("vue").PropType<string>;
43
+ required: true;
44
+ };
45
+ help: {
46
+ type: import("vue").PropType<string>;
47
+ };
48
+ modelValue: {
49
+ type: import("vue").PropType<any>;
50
+ };
51
+ multiple: {
52
+ type: import("vue").PropType<boolean>;
53
+ };
54
+ rules: {
55
+ type: import("vue").PropType<any[]>;
56
+ };
57
+ by: {
58
+ type: import("vue").PropType<string>;
59
+ required: true;
60
+ };
61
+ }>> & {
62
+ "onUpdate:modelValue"?: ((val: any[]) => any) | undefined;
63
+ }, {}, {}>;
64
+ export default _default;