@winchsa/ui 0.1.0

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 (305) hide show
  1. package/README.md +166 -0
  2. package/dist/components/Breadcrumbs.vue +46 -0
  3. package/dist/components/Breadcrumbs.vue.d.ts +6 -0
  4. package/dist/components/Drawer.vue +60 -0
  5. package/dist/components/Drawer.vue.d.ts +44 -0
  6. package/dist/components/IconBtn.vue +18 -0
  7. package/dist/components/IconBtn.vue.d.ts +30 -0
  8. package/dist/components/Modal.vue +155 -0
  9. package/dist/components/Modal.vue.d.ts +0 -0
  10. package/dist/components/SiteTitle.vue +14 -0
  11. package/dist/components/SiteTitle.vue.d.ts +2 -0
  12. package/dist/components/Toaster.vue +19 -0
  13. package/dist/components/Toaster.vue.d.ts +5 -0
  14. package/dist/components/cards/CheckboxesCard.vue +76 -0
  15. package/dist/components/cards/CheckboxesCard.vue.d.ts +20 -0
  16. package/dist/components/cards/HeaderCard.vue +31 -0
  17. package/dist/components/cards/HeaderCard.vue.d.ts +8 -0
  18. package/dist/components/cards/ImageCard.vue +73 -0
  19. package/dist/components/cards/ImageCard.vue.d.ts +63 -0
  20. package/dist/components/cards/InputCard.vue +60 -0
  21. package/dist/components/cards/InputCard.vue.d.ts +41 -0
  22. package/dist/components/cards/StaticCard.vue +37 -0
  23. package/dist/components/cards/StaticCard.vue.d.ts +33 -0
  24. package/dist/components/core/AppBarSearch.vue +345 -0
  25. package/dist/components/core/AppBarSearch.vue.d.ts +1587 -0
  26. package/dist/components/core/AppDrawerHeaderSection.vue +21 -0
  27. package/dist/components/core/AppDrawerHeaderSection.vue.d.ts +30 -0
  28. package/dist/components/core/AppSearchHeader.vue +72 -0
  29. package/dist/components/core/AppSearchHeader.vue.d.ts +7 -0
  30. package/dist/components/core/AppStepper.vue +232 -0
  31. package/dist/components/core/AppStepper.vue.d.ts +25 -0
  32. package/dist/components/core/CustomizerSection.vue +19 -0
  33. package/dist/components/core/CustomizerSection.vue.d.ts +25 -0
  34. package/dist/components/core/DialogCloseBtn.vue +20 -0
  35. package/dist/components/core/DialogCloseBtn.vue.d.ts +9 -0
  36. package/dist/components/core/MoreBtn.vue +27 -0
  37. package/dist/components/core/MoreBtn.vue.d.ts +25 -0
  38. package/dist/components/core/ScrollToTop.vue +39 -0
  39. package/dist/components/core/ScrollToTop.vue.d.ts +2 -0
  40. package/dist/components/core/app-form-elements/AppCombobox.vue +67 -0
  41. package/dist/components/core/app-form-elements/AppCombobox.vue.d.ts +0 -0
  42. package/dist/components/core/app-form-elements/AppSelect.vue +98 -0
  43. package/dist/components/core/app-form-elements/AppSelect.vue.d.ts +0 -0
  44. package/dist/components/core/app-form-elements/AppSwitch.vue +59 -0
  45. package/dist/components/core/app-form-elements/AppSwitch.vue.d.ts +27 -0
  46. package/dist/components/core/app-form-elements/AppTextField.vue +66 -0
  47. package/dist/components/core/app-form-elements/AppTextField.vue.d.ts +26 -0
  48. package/dist/components/core/app-form-elements/AppTextarea.vue +69 -0
  49. package/dist/components/core/app-form-elements/AppTextarea.vue.d.ts +26 -0
  50. package/dist/components/core/app-form-elements/CustomCheckboxes.vue +69 -0
  51. package/dist/components/core/app-form-elements/CustomCheckboxes.vue.d.ts +39 -0
  52. package/dist/components/core/app-form-elements/CustomCheckboxesWithIcon.vue +80 -0
  53. package/dist/components/core/app-form-elements/CustomCheckboxesWithIcon.vue.d.ts +39 -0
  54. package/dist/components/core/app-form-elements/CustomCheckboxesWithImage.vue +67 -0
  55. package/dist/components/core/app-form-elements/CustomCheckboxesWithImage.vue.d.ts +15 -0
  56. package/dist/components/core/app-form-elements/CustomRadios.vue +69 -0
  57. package/dist/components/core/app-form-elements/CustomRadios.vue.d.ts +40 -0
  58. package/dist/components/core/app-form-elements/CustomRadiosWithIcon.vue +98 -0
  59. package/dist/components/core/app-form-elements/CustomRadiosWithIcon.vue.d.ts +45 -0
  60. package/dist/components/core/app-form-elements/CustomRadiosWithImage.vue +69 -0
  61. package/dist/components/core/app-form-elements/CustomRadiosWithImage.vue.d.ts +53 -0
  62. package/dist/components/core/cards/AppCard.vue +45 -0
  63. package/dist/components/core/cards/AppCard.vue.d.ts +26 -0
  64. package/dist/components/core/cards/AppCardActions.vue +126 -0
  65. package/dist/components/core/cards/AppCardActions.vue.d.ts +79 -0
  66. package/dist/components/core/cards/CardStatisticsHorizontal.vue +29 -0
  67. package/dist/components/core/cards/CardStatisticsHorizontal.vue.d.ts +10 -0
  68. package/dist/components/forms/Accordion.vue +43 -0
  69. package/dist/components/forms/Accordion.vue.d.ts +35 -0
  70. package/dist/components/forms/AppLabel.vue +47 -0
  71. package/dist/components/forms/AppLabel.vue.d.ts +36 -0
  72. package/dist/components/forms/AppLink.vue +50 -0
  73. package/dist/components/forms/AppLink.vue.d.ts +27 -0
  74. package/dist/components/forms/AppNumberField.vue +85 -0
  75. package/dist/components/forms/AppNumberField.vue.d.ts +45 -0
  76. package/dist/components/forms/AppOtpInput.vue +84 -0
  77. package/dist/components/forms/AppOtpInput.vue.d.ts +16 -0
  78. package/dist/components/forms/AttachmentCropperInput.vue +228 -0
  79. package/dist/components/forms/AttachmentCropperInput.vue.d.ts +25 -0
  80. package/dist/components/forms/AttachmentInput.vue +116 -0
  81. package/dist/components/forms/AttachmentInput.vue.d.ts +20 -0
  82. package/dist/components/forms/AutocompleteInput.vue +759 -0
  83. package/dist/components/forms/AutocompleteInput.vue.d.ts +0 -0
  84. package/dist/components/forms/BankSelect.vue +43 -0
  85. package/dist/components/forms/BankSelect.vue.d.ts +19 -0
  86. package/dist/components/forms/BaseButton.vue +42 -0
  87. package/dist/components/forms/BaseButton.vue.d.ts +31 -0
  88. package/dist/components/forms/CounterInput.vue +71 -0
  89. package/dist/components/forms/CounterInput.vue.d.ts +15 -0
  90. package/dist/components/forms/DatePicker.vue +400 -0
  91. package/dist/components/forms/DatePicker.vue.d.ts +34 -0
  92. package/dist/components/forms/DatePickerRange.vue +129 -0
  93. package/dist/components/forms/DatePickerRange.vue.d.ts +23 -0
  94. package/dist/components/forms/DraggedUploadFile.vue +120 -0
  95. package/dist/components/forms/DraggedUploadFile.vue.d.ts +10 -0
  96. package/dist/components/forms/ImageCardInput.vue +234 -0
  97. package/dist/components/forms/ImageCardInput.vue.d.ts +0 -0
  98. package/dist/components/forms/InputValidationWrapper.vue +24 -0
  99. package/dist/components/forms/InputValidationWrapper.vue.d.ts +33 -0
  100. package/dist/components/forms/LicensePlateInput.vue +159 -0
  101. package/dist/components/forms/LicensePlateInput.vue.d.ts +16 -0
  102. package/dist/components/forms/ManualDate.vue +262 -0
  103. package/dist/components/forms/ManualDate.vue.d.ts +17 -0
  104. package/dist/components/forms/MobileInput.vue +118 -0
  105. package/dist/components/forms/MobileInput.vue.d.ts +49 -0
  106. package/dist/components/forms/PasswordInput.vue +29 -0
  107. package/dist/components/forms/PasswordInput.vue.d.ts +13 -0
  108. package/dist/components/forms/RangeInput.vue +48 -0
  109. package/dist/components/forms/RangeInput.vue.d.ts +5 -0
  110. package/dist/components/forms/Tabs.vue +35 -0
  111. package/dist/components/forms/Tabs.vue.d.ts +42 -0
  112. package/dist/components/forms/TimePicker.vue +370 -0
  113. package/dist/components/forms/TimePicker.vue.d.ts +23 -0
  114. package/dist/components/icons/EndMarker.vue +25 -0
  115. package/dist/components/icons/EndMarker.vue.d.ts +17 -0
  116. package/dist/components/icons/RedXIcon.vue +36 -0
  117. package/dist/components/icons/RedXIcon.vue.d.ts +2 -0
  118. package/dist/components/icons/StarFillIcon.vue +28 -0
  119. package/dist/components/icons/StarFillIcon.vue.d.ts +2 -0
  120. package/dist/components/icons/StartMarker.vue +25 -0
  121. package/dist/components/icons/StartMarker.vue.d.ts +17 -0
  122. package/dist/components/icons/WorkerIcon.vue +39 -0
  123. package/dist/components/icons/WorkerIcon.vue.d.ts +2 -0
  124. package/dist/components/loading/LoadingBar.vue +31 -0
  125. package/dist/components/loading/LoadingBar.vue.d.ts +5 -0
  126. package/dist/components/loading/LoadingDialog.vue +41 -0
  127. package/dist/components/loading/LoadingDialog.vue.d.ts +11 -0
  128. package/dist/components/loading/LoadingItem.vue +66 -0
  129. package/dist/components/loading/LoadingItem.vue.d.ts +47 -0
  130. package/dist/components/table/DataTable.vue +319 -0
  131. package/dist/components/table/DataTable.vue.d.ts +0 -0
  132. package/dist/components/table/EditableDataTable.vue +329 -0
  133. package/dist/components/table/EditableDataTable.vue.d.ts +73 -0
  134. package/dist/components/table/EditableDataTableRow.vue +243 -0
  135. package/dist/components/table/EditableDataTableRow.vue.d.ts +18 -0
  136. package/dist/components/table/FilterGenerator.vue +232 -0
  137. package/dist/components/table/FilterGenerator.vue.d.ts +14 -0
  138. package/dist/components/table/StaticTable.vue +152 -0
  139. package/dist/components/table/StaticTable.vue.d.ts +25 -0
  140. package/dist/components/table/TablePagination.vue +73 -0
  141. package/dist/components/table/TablePagination.vue.d.ts +13 -0
  142. package/dist/composables/use-is-mobile.d.ts +1 -0
  143. package/dist/composables/use-is-mobile.js +10 -0
  144. package/dist/composables/use-is-mobile.mjs +4 -0
  145. package/dist/composables/use-table-filters.d.ts +23 -0
  146. package/dist/composables/use-table-filters.js +196 -0
  147. package/dist/composables/use-table-filters.mjs +183 -0
  148. package/dist/fonts/NotoSans-Medium.ttf +0 -0
  149. package/dist/fonts/NotoSansArabic-Medium.ttf +0 -0
  150. package/dist/fonts/saudi_riyal_symbol/saudi_riyal_symbol.eot +0 -0
  151. package/dist/fonts/saudi_riyal_symbol/saudi_riyal_symbol.svg +9 -0
  152. package/dist/fonts/saudi_riyal_symbol/saudi_riyal_symbol.ttf +0 -0
  153. package/dist/fonts/saudi_riyal_symbol/saudi_riyal_symbol.woff +0 -0
  154. package/dist/fonts/saudi_riyal_symbol/saudi_riyal_symbol.woff2 +0 -0
  155. package/dist/images/avatar.png +0 -0
  156. package/dist/images/sa.svg +1 -0
  157. package/dist/images/successful-registration.svg +15 -0
  158. package/dist/index.d.ts +66 -0
  159. package/dist/index.js +447 -0
  160. package/dist/index.mjs +128 -0
  161. package/dist/styles/@core/scss/base/_components.scss +164 -0
  162. package/dist/styles/@core/scss/base/_dark.scss +16 -0
  163. package/dist/styles/@core/scss/base/_default-layout-w-vertical-nav.scss +106 -0
  164. package/dist/styles/@core/scss/base/_default-layout.scss +16 -0
  165. package/dist/styles/@core/scss/base/_index.scss +47 -0
  166. package/dist/styles/@core/scss/base/_layouts.scss +63 -0
  167. package/dist/styles/@core/scss/base/_misc.scss +20 -0
  168. package/dist/styles/@core/scss/base/_mixins.scss +84 -0
  169. package/dist/styles/@core/scss/base/_route-transitions.scss +70 -0
  170. package/dist/styles/@core/scss/base/_utilities.scss +418 -0
  171. package/dist/styles/@core/scss/base/_utils.scss +100 -0
  172. package/dist/styles/@core/scss/base/_variables.scss +190 -0
  173. package/dist/styles/@core/scss/base/_vertical-nav.scss +264 -0
  174. package/dist/styles/@core/scss/base/libs/_perfect-scrollbar.scss +35 -0
  175. package/dist/styles/@core/scss/base/libs/vuetify/_index.scss +1 -0
  176. package/dist/styles/@core/scss/base/libs/vuetify/_overrides.scss +385 -0
  177. package/dist/styles/@core/scss/base/libs/vuetify/_variables.scss +48 -0
  178. package/dist/styles/@core/scss/base/placeholders/_default-layout-vertical-nav.scss +48 -0
  179. package/dist/styles/@core/scss/base/placeholders/_default-layout.scss +3 -0
  180. package/dist/styles/@core/scss/base/placeholders/_index.scss +5 -0
  181. package/dist/styles/@core/scss/base/placeholders/_misc.scss +7 -0
  182. package/dist/styles/@core/scss/base/placeholders/_nav.scss +26 -0
  183. package/dist/styles/@core/scss/base/placeholders/_vertical-nav.scss +84 -0
  184. package/dist/styles/@core/scss/base/skins/_bordered.scss +60 -0
  185. package/dist/styles/@core/scss/base/skins/_index.scss +1 -0
  186. package/dist/styles/@core/scss/template/_components.scss +1035 -0
  187. package/dist/styles/@core/scss/template/_default-layout-w-vertical-nav.scss +20 -0
  188. package/dist/styles/@core/scss/template/_utilities.scss +20 -0
  189. package/dist/styles/@core/scss/template/_variables.scss +67 -0
  190. package/dist/styles/@core/scss/template/_vertical-nav.scss +41 -0
  191. package/dist/styles/@core/scss/template/index.css +18764 -0
  192. package/dist/styles/@core/scss/template/index.scss +15 -0
  193. package/dist/styles/@core/scss/template/libs/apex-chart.css +90 -0
  194. package/dist/styles/@core/scss/template/libs/apex-chart.scss +99 -0
  195. package/dist/styles/@core/scss/template/libs/shepherd.css +82 -0
  196. package/dist/styles/@core/scss/template/libs/shepherd.scss +88 -0
  197. package/dist/styles/@core/scss/template/libs/vuetify/_variables.scss +461 -0
  198. package/dist/styles/@core/scss/template/libs/vuetify/index.css +741 -0
  199. package/dist/styles/@core/scss/template/libs/vuetify/index.scss +1 -0
  200. package/dist/styles/@core/scss/template/pages/misc.css +16 -0
  201. package/dist/styles/@core/scss/template/pages/misc.scss +20 -0
  202. package/dist/styles/@core/scss/template/placeholders/_default-layout-vertical-nav.scss +9 -0
  203. package/dist/styles/@core/scss/template/placeholders/_index.scss +3 -0
  204. package/dist/styles/@core/scss/template/placeholders/_nav.scss +15 -0
  205. package/dist/styles/@core/scss/template/placeholders/_vertical-nav.scss +18 -0
  206. package/dist/styles/@core/scss/template/skins/_bordered.scss +36 -0
  207. package/dist/styles/@core/scss/template/skins/_index.scss +1 -0
  208. package/dist/styles/@layouts/styles/_classes.scss +3 -0
  209. package/dist/styles/@layouts/styles/_dashboard-layout.scss +43 -0
  210. package/dist/styles/@layouts/styles/_global.scss +10 -0
  211. package/dist/styles/@layouts/styles/_mixins.scss +28 -0
  212. package/dist/styles/@layouts/styles/_placeholders.scss +53 -0
  213. package/dist/styles/@layouts/styles/_rtl.scss +7 -0
  214. package/dist/styles/@layouts/styles/_variables.scss +22 -0
  215. package/dist/styles/@layouts/styles/index.css +14 -0
  216. package/dist/styles/@layouts/styles/index.scss +2 -0
  217. package/dist/styles/assets/scss/styles.css +16099 -0
  218. package/dist/styles/assets/scss/styles.scss +246 -0
  219. package/dist/styles/assets/scss/variables/_template.scss +1 -0
  220. package/dist/styles/assets/scss/variables/_vuetify.scss +1 -0
  221. package/dist/types.d.ts +226 -0
  222. package/dist/utils/apiUrl.d.ts +1 -0
  223. package/dist/utils/apiUrl.js +15 -0
  224. package/dist/utils/apiUrl.mjs +8 -0
  225. package/dist/utils/client.d.ts +9 -0
  226. package/dist/utils/client.js +39 -0
  227. package/dist/utils/client.mjs +25 -0
  228. package/dist/utils/files.d.ts +2 -0
  229. package/dist/utils/files.js +35 -0
  230. package/dist/utils/files.mjs +22 -0
  231. package/dist/utils/formValidation.d.ts +7 -0
  232. package/dist/utils/formValidation.js +20 -0
  233. package/dist/utils/formValidation.mjs +13 -0
  234. package/dist/utils/formatters.d.ts +12 -0
  235. package/dist/utils/formatters.js +84 -0
  236. package/dist/utils/formatters.mjs +56 -0
  237. package/dist/utils/index.d.ts +9 -0
  238. package/dist/utils/index.js +104 -0
  239. package/dist/utils/index.mjs +9 -0
  240. package/dist/utils/queryParams.d.ts +4 -0
  241. package/dist/utils/queryParams.js +26 -0
  242. package/dist/utils/queryParams.mjs +18 -0
  243. package/dist/utils/ruleValidator.d.ts +28 -0
  244. package/dist/utils/ruleValidator.js +158 -0
  245. package/dist/utils/ruleValidator.mjs +144 -0
  246. package/dist/utils/toaster.d.ts +12 -0
  247. package/dist/utils/toaster.js +71 -0
  248. package/dist/utils/toaster.mjs +59 -0
  249. package/dist/utils/utils.d.ts +8 -0
  250. package/dist/utils/utils.js +70 -0
  251. package/dist/utils/utils.mjs +56 -0
  252. package/package.json +79 -0
  253. package/src/styles/@core/scss/base/_components.scss +164 -0
  254. package/src/styles/@core/scss/base/_dark.scss +16 -0
  255. package/src/styles/@core/scss/base/_default-layout-w-vertical-nav.scss +106 -0
  256. package/src/styles/@core/scss/base/_default-layout.scss +16 -0
  257. package/src/styles/@core/scss/base/_index.scss +47 -0
  258. package/src/styles/@core/scss/base/_layouts.scss +63 -0
  259. package/src/styles/@core/scss/base/_misc.scss +20 -0
  260. package/src/styles/@core/scss/base/_mixins.scss +84 -0
  261. package/src/styles/@core/scss/base/_route-transitions.scss +70 -0
  262. package/src/styles/@core/scss/base/_utilities.scss +418 -0
  263. package/src/styles/@core/scss/base/_utils.scss +100 -0
  264. package/src/styles/@core/scss/base/_variables.scss +190 -0
  265. package/src/styles/@core/scss/base/_vertical-nav.scss +264 -0
  266. package/src/styles/@core/scss/base/libs/_perfect-scrollbar.scss +35 -0
  267. package/src/styles/@core/scss/base/libs/vuetify/_index.scss +1 -0
  268. package/src/styles/@core/scss/base/libs/vuetify/_overrides.scss +385 -0
  269. package/src/styles/@core/scss/base/libs/vuetify/_variables.scss +48 -0
  270. package/src/styles/@core/scss/base/placeholders/_default-layout-vertical-nav.scss +48 -0
  271. package/src/styles/@core/scss/base/placeholders/_default-layout.scss +3 -0
  272. package/src/styles/@core/scss/base/placeholders/_index.scss +5 -0
  273. package/src/styles/@core/scss/base/placeholders/_misc.scss +7 -0
  274. package/src/styles/@core/scss/base/placeholders/_nav.scss +26 -0
  275. package/src/styles/@core/scss/base/placeholders/_vertical-nav.scss +84 -0
  276. package/src/styles/@core/scss/base/skins/_bordered.scss +60 -0
  277. package/src/styles/@core/scss/base/skins/_index.scss +1 -0
  278. package/src/styles/@core/scss/template/_components.scss +1035 -0
  279. package/src/styles/@core/scss/template/_default-layout-w-vertical-nav.scss +20 -0
  280. package/src/styles/@core/scss/template/_utilities.scss +20 -0
  281. package/src/styles/@core/scss/template/_variables.scss +67 -0
  282. package/src/styles/@core/scss/template/_vertical-nav.scss +41 -0
  283. package/src/styles/@core/scss/template/index.scss +15 -0
  284. package/src/styles/@core/scss/template/libs/apex-chart.scss +99 -0
  285. package/src/styles/@core/scss/template/libs/shepherd.scss +88 -0
  286. package/src/styles/@core/scss/template/libs/vuetify/_variables.scss +461 -0
  287. package/src/styles/@core/scss/template/libs/vuetify/index.scss +1 -0
  288. package/src/styles/@core/scss/template/pages/misc.scss +20 -0
  289. package/src/styles/@core/scss/template/placeholders/_default-layout-vertical-nav.scss +9 -0
  290. package/src/styles/@core/scss/template/placeholders/_index.scss +3 -0
  291. package/src/styles/@core/scss/template/placeholders/_nav.scss +15 -0
  292. package/src/styles/@core/scss/template/placeholders/_vertical-nav.scss +18 -0
  293. package/src/styles/@core/scss/template/skins/_bordered.scss +36 -0
  294. package/src/styles/@core/scss/template/skins/_index.scss +1 -0
  295. package/src/styles/@layouts/styles/_classes.scss +3 -0
  296. package/src/styles/@layouts/styles/_dashboard-layout.scss +43 -0
  297. package/src/styles/@layouts/styles/_global.scss +10 -0
  298. package/src/styles/@layouts/styles/_mixins.scss +28 -0
  299. package/src/styles/@layouts/styles/_placeholders.scss +53 -0
  300. package/src/styles/@layouts/styles/_rtl.scss +7 -0
  301. package/src/styles/@layouts/styles/_variables.scss +22 -0
  302. package/src/styles/@layouts/styles/index.scss +2 -0
  303. package/src/styles/assets/scss/styles.scss +246 -0
  304. package/src/styles/assets/scss/variables/_template.scss +1 -0
  305. package/src/styles/assets/scss/variables/_vuetify.scss +1 -0
@@ -0,0 +1,228 @@
1
+ <script setup>
2
+ import Cropper from "cropperjs";
3
+ import { ref, computed, watch, nextTick } from "vue";
4
+ import "cropperjs/dist/cropper.css";
5
+ import { useI18n } from "vue-i18n";
6
+ import { VIcon, VBtn, VValidation, VSlider } from "vuetify/components";
7
+ import { ruleValidator } from "../../utils/ruleValidator";
8
+ import Modal from "../Modal.vue";
9
+ import { generateUniqueId } from "../../utils/utils";
10
+ import BaseButton from "./BaseButton.vue";
11
+ const props = defineProps({
12
+ validTypes: { type: Array, required: false, default: () => ["image/png", "image/jpeg", "image/jpg"] },
13
+ rules: { type: Array, required: false },
14
+ multiple: { type: Boolean, required: false, default: false },
15
+ modelValue: { type: [Object, Array, null], required: true },
16
+ sizeInMB: { type: Number, required: false, default: 3 },
17
+ showPreview: { type: Boolean, required: false, default: true },
18
+ cropWidth: { type: Number, required: false, default: 120 },
19
+ cropHeight: { type: Number, required: false, default: 40 }
20
+ });
21
+ const emit = defineEmits(["update:model-value"]);
22
+ const { locale } = useI18n();
23
+ const { fileValidator } = ruleValidator();
24
+ const imageUploadInput = ref(null);
25
+ const attachments = ref([]);
26
+ const cropperDialog = ref(false);
27
+ const cropImageSrc = ref(null);
28
+ const selectedFile = ref(null);
29
+ const cropperInstance = ref(null);
30
+ const zoomLevel = ref(1);
31
+ const initialZoom = ref(1);
32
+ const cropperImage = ref(null);
33
+ const allowMultipleAttachments = computed(
34
+ () => props.multiple || !props.showPreview ? true : attachments.value?.length === 0
35
+ );
36
+ const onImageChanged = (e) => {
37
+ const target = e.target;
38
+ const file = target.files?.[0];
39
+ const isValid = fileValidator(file, props.sizeInMB, props.validTypes);
40
+ if (isValid && file) {
41
+ selectedFile.value = file;
42
+ cropImageSrc.value = URL.createObjectURL(file);
43
+ cropperDialog.value = true;
44
+ }
45
+ };
46
+ const initCropper = () => {
47
+ if (cropperInstance.value) {
48
+ cropperInstance.value.destroy();
49
+ }
50
+ if (cropperImage.value) {
51
+ cropperInstance.value = new Cropper(cropperImage.value, {
52
+ viewMode: 1,
53
+ responsive: true,
54
+ zoomable: true,
55
+ scalable: false,
56
+ movable: true,
57
+ wheelZoomRatio: 0,
58
+ zoomOnWheel: false,
59
+ ready() {
60
+ const data = cropperInstance.value?.getImageData();
61
+ initialZoom.value = data ? Math.min(data.width / data.naturalWidth, data.height / data.naturalHeight) : 1;
62
+ zoomLevel.value = initialZoom.value;
63
+ }
64
+ });
65
+ }
66
+ };
67
+ const closeCropper = () => {
68
+ cropperDialog.value = false;
69
+ selectedFile.value = null;
70
+ if (imageUploadInput.value) {
71
+ imageUploadInput.value.value = "";
72
+ }
73
+ };
74
+ const resizeCanvas = (canvas, width, height) => {
75
+ const offscreenCanvas = document.createElement("canvas");
76
+ offscreenCanvas.width = width;
77
+ offscreenCanvas.height = height;
78
+ const ctx = offscreenCanvas.getContext("2d");
79
+ if (ctx) {
80
+ ctx.drawImage(canvas, 0, 0, width, height);
81
+ }
82
+ return offscreenCanvas;
83
+ };
84
+ const cropImage = () => {
85
+ if (!cropperInstance.value) {
86
+ return;
87
+ }
88
+ const targetWidth = props.cropWidth;
89
+ const targetHeight = props.cropHeight;
90
+ let canvas = cropperInstance.value.getCroppedCanvas();
91
+ if (!canvas) {
92
+ return;
93
+ }
94
+ if (canvas.width !== targetWidth || canvas.height !== targetHeight) {
95
+ canvas = resizeCanvas(canvas, targetWidth, targetHeight);
96
+ }
97
+ canvas.toBlob((blob) => {
98
+ if (blob && selectedFile.value) {
99
+ const croppedFile = new File([blob], selectedFile.value.name, { type: selectedFile.value.type });
100
+ const attachment = {
101
+ id: generateUniqueId(),
102
+ src: URL.createObjectURL(croppedFile),
103
+ file: croppedFile
104
+ };
105
+ attachments.value.push(attachment);
106
+ emit("update:model-value", props.multiple ? attachments.value : attachment);
107
+ cropperDialog.value = false;
108
+ }
109
+ }, selectedFile.value?.type);
110
+ };
111
+ const removeImageCopy = (id) => {
112
+ const index = attachments.value.findIndex((attachment) => attachment.id === id);
113
+ if (index > -1) {
114
+ attachments.value.splice(index, 1);
115
+ emit("update:model-value", props.multiple ? attachments.value : attachments.value[0] || null);
116
+ }
117
+ };
118
+ watch(zoomLevel, async (newZoom) => {
119
+ await nextTick(() => {
120
+ if (cropperInstance.value) {
121
+ cropperInstance.value.zoomTo(newZoom);
122
+ }
123
+ });
124
+ });
125
+ </script>
126
+
127
+ <template>
128
+ <div class="d-flex flex-column">
129
+ <div class="d-flex align-center gap-3">
130
+ <BaseButton
131
+ v-if="allowMultipleAttachments"
132
+ size="48"
133
+ color="gray-200"
134
+ elevation="0"
135
+ class="app-z-40"
136
+ @click="imageUploadInput?.click()"
137
+ >
138
+ <VIcon size="28" icon="tabler-upload" color="on-gray-200" />
139
+ </BaseButton>
140
+
141
+ <TransitionGroup
142
+ v-if="showPreview"
143
+ tag="div"
144
+ class="d-flex align-center flex-wrap sb-w-full gap-3"
145
+ enter-active-class="slide-in-right"
146
+ leave-active-class="slide-out-right"
147
+ mode="out-in"
148
+ >
149
+ <div
150
+ v-for="attachment in attachments"
151
+ :key="attachment.id"
152
+ class="app-w-48px app-h-48px bg-gray-50 app-rounded-6 position-relative d-flex align-center justify-center"
153
+ >
154
+ <img v-if="attachment.src" :src="attachment.src" class="app-rounded-6 overflow-hidden app-w-48px app-h-48px">
155
+ <VIcon v-else color="gray-600">
156
+ tabler-pdf
157
+ </VIcon>
158
+ <VBtn
159
+ icon="tabler-x"
160
+ size="20"
161
+ color="red"
162
+ small
163
+ class="d-flex align-center justify-center position-absolute app-top--8px app-z-10"
164
+ :class="locale === 'en' ? 'app-right--8px' : 'app-left--8px'"
165
+ @click="removeImageCopy(attachment.id)"
166
+ />
167
+ </div>
168
+ </TransitionGroup>
169
+ </div>
170
+
171
+ <VValidation
172
+ v-slot="{ errorMessages: validationErrors, isValid }"
173
+ ref="attachmentInputRef"
174
+ v-model="attachments"
175
+ :rules="rules"
176
+ validate-on="submit lazy"
177
+ >
178
+ <div class="d-flex flex-column">
179
+ <input
180
+ ref="imageUploadInput"
181
+ class="d-none"
182
+ type="file"
183
+ :disabled="!allowMultipleAttachments"
184
+ :accept="validTypes?.join(',')"
185
+ @change="onImageChanged($event)"
186
+ >
187
+ <VMessages class="mt-1 d-block" :messages="validationErrors.value" :active="isValid.value === false" />
188
+ </div>
189
+ </VValidation>
190
+
191
+ <!-- Cropper Dialog -->
192
+ <Modal
193
+ v-model="cropperDialog"
194
+ persistent
195
+ width="500"
196
+ :has-icon="false"
197
+ @save="cropImage"
198
+ @cancel="closeCropper"
199
+ >
200
+ <img
201
+ v-if="cropImageSrc"
202
+ ref="cropperImage"
203
+ :src="cropImageSrc"
204
+ style="max-width: 100%; margin-bottom: 1px;"
205
+ @load="initCropper"
206
+ >
207
+
208
+ <template #additional-actions>
209
+ <VSlider
210
+ v-model="zoomLevel"
211
+ class="pa-3 mt-2 flex-grow-1"
212
+ :min="initialZoom"
213
+ :max="initialZoom * 3"
214
+ step="0.1"
215
+ density="comfortable"
216
+ track-size="6"
217
+ thumb-size="18"
218
+ prepend-icon="tabler-minus"
219
+ append-icon="tabler-plus"
220
+ />
221
+ </template>
222
+ </Modal>
223
+ </div>
224
+ </template>
225
+
226
+ <style scoped>
227
+ :deep(.cropper-container){width:auto!important}:global(.cropper-line),:global(.cropper-point){background-color:rgb(var(--v-theme-primary))}:global(.cropper-view-box){outline-color:rgba(var(--v-theme-primary),.75)}
228
+ </style>
@@ -0,0 +1,25 @@
1
+ import 'cropperjs/dist/cropper.css';
2
+ import type { Attachment } from '../../types';
3
+ type __VLS_Props = {
4
+ validTypes?: string[];
5
+ rules?: ((value: unknown) => typeof value | string)[];
6
+ multiple?: boolean;
7
+ modelValue: Attachment | Attachment[] | null;
8
+ sizeInMB?: number;
9
+ showPreview?: boolean;
10
+ cropWidth?: number;
11
+ cropHeight?: number;
12
+ };
13
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
14
+ "update:model-value": (value: Attachment | Attachment[]) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
+ "onUpdate:model-value"?: ((value: Attachment | Attachment[]) => any) | undefined;
17
+ }>, {
18
+ multiple: boolean;
19
+ validTypes: string[];
20
+ sizeInMB: number;
21
+ showPreview: boolean;
22
+ cropWidth: number;
23
+ cropHeight: number;
24
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
25
+ export default _default;
@@ -0,0 +1,116 @@
1
+ <script setup>
2
+ import { VBtn, VIcon, VValidation, VMessages } from "vuetify/components";
3
+ import { ref, computed } from "vue";
4
+ import { useI18n } from "vue-i18n";
5
+ import { generateUniqueId } from "../../utils/utils";
6
+ import { ruleValidator } from "../../utils/ruleValidator";
7
+ import BaseButton from "./BaseButton.vue";
8
+ const props = defineProps({
9
+ validTypes: { type: Array, required: false, default: () => ["image/png", "image/jpeg", "image/jpg"] },
10
+ rules: { type: Array, required: false },
11
+ multiple: { type: Boolean, required: false, default: false },
12
+ modelValue: { type: [Object, Array, null], required: true },
13
+ sizeInMB: { type: Number, required: false, default: 3 },
14
+ showPreview: { type: Boolean, required: false, default: true }
15
+ });
16
+ const emit = defineEmits(["update:model-value"]);
17
+ const { locale } = useI18n();
18
+ const { fileValidator } = ruleValidator();
19
+ const imageUploadInput = ref(null);
20
+ const attachments = ref([]);
21
+ const allowMultipleAttachments = computed(() => props.multiple || !props.showPreview ? true : attachments.value?.length === 0 && attachments.value?.length < 1);
22
+ const onImageChanged = (e, validate) => {
23
+ const target = e.target;
24
+ const file = target.files?.[0];
25
+ const isVaild = fileValidator(file, props.sizeInMB, props.validTypes);
26
+ if (isVaild && file) {
27
+ const attachment = {
28
+ id: generateUniqueId(),
29
+ src: file.type !== "application/pdf" ? createImageUrl(file) : "",
30
+ file
31
+ };
32
+ attachments.value.push(attachment);
33
+ validate();
34
+ emit("update:model-value", props.multiple ? attachments.value : attachments.value[attachments.value.length - 1]);
35
+ if (imageUploadInput.value) {
36
+ imageUploadInput.value.value = "";
37
+ }
38
+ }
39
+ };
40
+ function createImageUrl(file) {
41
+ const imageUrl = URL.createObjectURL(file);
42
+ return imageUrl;
43
+ }
44
+ const removeImageCopy = (id) => {
45
+ const attachmentIndex = attachments.value.findIndex((attachment) => attachment.id === id);
46
+ if (attachmentIndex > -1) {
47
+ attachments.value.splice(attachmentIndex, 1);
48
+ emit("update:model-value", props.multiple ? attachments.value : attachments.value[0]);
49
+ }
50
+ };
51
+ </script>
52
+
53
+ <template>
54
+ <div class="d-flex flex-column">
55
+ <div class="d-flex align-center gap-3">
56
+ <BaseButton
57
+ v-if="allowMultipleAttachments"
58
+ size="48"
59
+ color="gray-200"
60
+ elevation="0"
61
+ class="app-z-40"
62
+ @click="imageUploadInput?.click()"
63
+ >
64
+ <VIcon
65
+ size="28"
66
+ icon="tabler-upload"
67
+ color="on-gray-200"
68
+ />
69
+ </BaseButton>
70
+ <TransitionGroup
71
+ v-if="showPreview"
72
+ tag="div"
73
+ class="d-flex align-center flex-wrap sb-w-full gap-3"
74
+ enter-active-class="slide-in-right"
75
+ leave-active-class="slide-out-right"
76
+ mode="out-in"
77
+ >
78
+ <div v-for="attachment in attachments" :key="attachment.id" class="app-w-48px app-h-48px bg-gray-50 app-rounded-6 position-relative d-flex align-center justify-center">
79
+ <img v-if="attachment.src" :src="attachment.src" class="app-rounded-6 overflow-hidden app-w-48px app-h-48px">
80
+ <VIcon v-else color="gray-600">
81
+ tabler-pdf
82
+ </VIcon>
83
+ <VBtn
84
+ icon="tabler-x"
85
+ size="20"
86
+ color="red"
87
+ small
88
+ class="d-flex align-center justify-center position-absolute app-top--8px app-z-10"
89
+ :class="locale === 'en' ? 'app-right--8px' : 'app-left--8px'"
90
+ @click="removeImageCopy(attachment.id)"
91
+ />
92
+ </div>
93
+ </TransitionGroup>
94
+ </div>
95
+ <VValidation
96
+ v-slot="{ errorMessages: validationErrors, isValid, validate }"
97
+ ref="attachmentInputRef"
98
+ v-model="attachments"
99
+ :rules="rules"
100
+ validate-on="submit lazy"
101
+ >
102
+ <div class="d-flex flex-column">
103
+ <input
104
+ ref="imageUploadInput"
105
+ class="d-none"
106
+ type="file"
107
+ :disabled="!allowMultipleAttachments"
108
+ :accept="validTypes?.join(',')"
109
+ @change="onImageChanged($event, validate)"
110
+ >
111
+
112
+ <VMessages class="mt-1 d-block" :messages="validationErrors.value" :active="isValid.value === false" />
113
+ </div>
114
+ </VValidation>
115
+ </div>
116
+ </template>
@@ -0,0 +1,20 @@
1
+ import type { Attachment } from '../../types';
2
+ type __VLS_Props = {
3
+ validTypes?: string[];
4
+ rules?: ((value: unknown) => typeof value | string)[];
5
+ multiple?: boolean;
6
+ modelValue: Attachment | Attachment[] | null;
7
+ sizeInMB?: number;
8
+ showPreview?: boolean;
9
+ };
10
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
11
+ "update:model-value": (value: Attachment | Attachment[]) => any;
12
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
13
+ "onUpdate:model-value"?: ((value: Attachment | Attachment[]) => any) | undefined;
14
+ }>, {
15
+ multiple: boolean;
16
+ validTypes: string[];
17
+ sizeInMB: number;
18
+ showPreview: boolean;
19
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
+ export default _default;