@uploadcare/file-uploader 1.21.0-alpha.3 → 1.22.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 (264) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +8 -2
  3. package/abstract/ActivityBlock.d.ts +0 -1
  4. package/abstract/ActivityBlock.d.ts.map +1 -1
  5. package/abstract/ActivityBlock.js +1 -1
  6. package/abstract/Block.d.ts +13 -2
  7. package/abstract/Block.d.ts.map +1 -1
  8. package/abstract/Block.js +35 -3
  9. package/abstract/CTX.d.ts +4 -4
  10. package/abstract/CTX.d.ts.map +1 -1
  11. package/abstract/CTX.js +2 -2
  12. package/abstract/SolutionBlock.d.ts +2 -2
  13. package/abstract/UploaderBlock.d.ts +9 -5
  14. package/abstract/UploaderBlock.d.ts.map +1 -1
  15. package/abstract/UploaderBlock.js +50 -13
  16. package/abstract/UploaderPublicApi.d.ts +2 -2
  17. package/abstract/UploaderPublicApi.d.ts.map +1 -1
  18. package/abstract/UploaderPublicApi.js +4 -4
  19. package/abstract/l10nProcessor.js +1 -1
  20. package/abstract/{LocaleManager.d.ts → managers/LocaleManager.d.ts} +8 -8
  21. package/abstract/{LocaleManager.d.ts.map → managers/LocaleManager.d.ts.map} +1 -1
  22. package/abstract/{LocaleManager.js → managers/LocaleManager.js} +8 -8
  23. package/abstract/{ModalManager.d.ts → managers/ModalManager.d.ts} +7 -7
  24. package/abstract/{ModalManager.d.ts.map → managers/ModalManager.d.ts.map} +1 -1
  25. package/abstract/{ModalManager.js → managers/ModalManager.js} +4 -3
  26. package/abstract/managers/SecureUploadsManager.d.ts +22 -0
  27. package/abstract/{SecureUploadsManager.d.ts.map → managers/SecureUploadsManager.d.ts.map} +1 -1
  28. package/abstract/{SecureUploadsManager.js → managers/SecureUploadsManager.js} +9 -5
  29. package/abstract/managers/TelemetryManager.d.ts +71 -0
  30. package/abstract/managers/TelemetryManager.d.ts.map +1 -0
  31. package/abstract/managers/TelemetryManager.js +218 -0
  32. package/abstract/{ValidationManager.d.ts → managers/ValidationManager.d.ts} +7 -7
  33. package/abstract/managers/ValidationManager.d.ts.map +1 -0
  34. package/abstract/{ValidationManager.js → managers/ValidationManager.js} +16 -14
  35. package/abstract/{a11y.d.ts → managers/a11y.d.ts} +2 -2
  36. package/abstract/managers/a11y.d.ts.map +1 -0
  37. package/abstract/{a11y.js → managers/a11y.js} +1 -1
  38. package/blocks/CameraSource/CameraSource.d.ts +2 -2
  39. package/blocks/CameraSource/CameraSource.d.ts.map +1 -1
  40. package/blocks/CameraSource/CameraSource.js +15 -3
  41. package/blocks/CloudImageEditor/src/CloudImageEditorBlock.d.ts +2 -1
  42. package/blocks/CloudImageEditor/src/CloudImageEditorBlock.d.ts.map +1 -1
  43. package/blocks/CloudImageEditor/src/CloudImageEditorBlock.js +20 -5
  44. package/blocks/CloudImageEditor/src/CropFrame.js +3 -3
  45. package/blocks/CloudImageEditor/src/EditorAspectRatioButtonControl.d.ts +14 -0
  46. package/blocks/CloudImageEditor/src/EditorAspectRatioButtonControl.d.ts.map +1 -0
  47. package/blocks/CloudImageEditor/src/EditorAspectRatioButtonControl.js +140 -0
  48. package/blocks/CloudImageEditor/src/EditorButtonControl.js +1 -1
  49. package/blocks/CloudImageEditor/src/EditorCropButtonControl.d.ts.map +1 -1
  50. package/blocks/CloudImageEditor/src/EditorCropButtonControl.js +9 -1
  51. package/blocks/CloudImageEditor/src/EditorFilterControl.d.ts.map +1 -1
  52. package/blocks/CloudImageEditor/src/EditorFilterControl.js +7 -1
  53. package/blocks/CloudImageEditor/src/EditorImageCropper.d.ts.map +1 -1
  54. package/blocks/CloudImageEditor/src/EditorImageCropper.js +3 -3
  55. package/blocks/CloudImageEditor/src/EditorOperationControl.d.ts +1 -1
  56. package/blocks/CloudImageEditor/src/EditorOperationControl.d.ts.map +1 -1
  57. package/blocks/CloudImageEditor/src/EditorOperationControl.js +9 -3
  58. package/blocks/CloudImageEditor/src/EditorToolbar.d.ts +19 -7
  59. package/blocks/CloudImageEditor/src/EditorToolbar.d.ts.map +1 -1
  60. package/blocks/CloudImageEditor/src/EditorToolbar.js +88 -21
  61. package/blocks/CloudImageEditor/src/css/common.css +69 -7
  62. package/blocks/CloudImageEditor/src/index.d.ts +1 -0
  63. package/blocks/CloudImageEditor/src/index.js +1 -0
  64. package/blocks/CloudImageEditor/src/lib/parseCropPreset.d.ts +2 -1
  65. package/blocks/CloudImageEditor/src/lib/parseCropPreset.d.ts.map +1 -1
  66. package/blocks/CloudImageEditor/src/lib/parseCropPreset.js +74 -8
  67. package/blocks/CloudImageEditor/src/lib/parseCropPreset.test.d.ts +2 -0
  68. package/blocks/CloudImageEditor/src/lib/parseCropPreset.test.d.ts.map +1 -0
  69. package/blocks/CloudImageEditor/src/lib/parseCropPreset.test.js +35 -0
  70. package/blocks/CloudImageEditor/src/state.d.ts +2 -2
  71. package/blocks/CloudImageEditor/src/state.d.ts.map +1 -1
  72. package/blocks/CloudImageEditor/src/state.js +2 -2
  73. package/blocks/CloudImageEditor/src/svg-sprite.d.ts +1 -1
  74. package/blocks/CloudImageEditor/src/svg-sprite.d.ts.map +1 -1
  75. package/blocks/CloudImageEditor/src/svg-sprite.js +1 -1
  76. package/blocks/CloudImageEditor/src/toolbar-constants.d.ts +2 -2
  77. package/blocks/CloudImageEditor/src/toolbar-constants.d.ts.map +1 -1
  78. package/blocks/CloudImageEditor/src/toolbar-constants.js +3 -2
  79. package/blocks/CloudImageEditor/src/types.d.ts +2 -0
  80. package/blocks/CloudImageEditor/src/types.d.ts.map +1 -1
  81. package/blocks/CloudImageEditor/src/types.js +9 -1
  82. package/blocks/CloudImageEditor/src/utils/parseFilterValue.d.ts +11 -0
  83. package/blocks/CloudImageEditor/src/utils/parseFilterValue.d.ts.map +1 -0
  84. package/blocks/CloudImageEditor/src/utils/parseFilterValue.js +11 -0
  85. package/blocks/Config/Config.d.ts.map +1 -1
  86. package/blocks/Config/Config.js +6 -1
  87. package/blocks/Config/initialConfig.d.ts +1 -0
  88. package/blocks/Config/initialConfig.d.ts.map +1 -1
  89. package/blocks/Config/initialConfig.js +6 -2
  90. package/blocks/Config/normalizeConfigValue.d.ts.map +1 -1
  91. package/blocks/Config/normalizeConfigValue.js +3 -0
  92. package/blocks/Config/side-effects.d.ts +8 -4
  93. package/blocks/Config/side-effects.d.ts.map +1 -1
  94. package/blocks/Config/side-effects.js +115 -21
  95. package/blocks/DropArea/DropArea.d.ts +2 -2
  96. package/blocks/ExternalSource/ExternalSource.d.ts +2 -2
  97. package/blocks/ExternalSource/types.d.ts +0 -3
  98. package/blocks/ExternalSource/types.d.ts.map +1 -1
  99. package/blocks/ExternalSource/types.js +0 -4
  100. package/blocks/FileItem/FileItem.d.ts +2 -3
  101. package/blocks/FileItem/FileItem.d.ts.map +1 -1
  102. package/blocks/FileItem/FileItem.js +20 -18
  103. package/blocks/FileItem/FileItemConfig.d.ts +1 -1
  104. package/blocks/FileItem/FileItemConfig.d.ts.map +1 -1
  105. package/blocks/FileItem/FileItemConfig.js +3 -3
  106. package/blocks/Modal/Modal.d.ts +6 -6
  107. package/blocks/Modal/Modal.d.ts.map +1 -1
  108. package/blocks/Modal/Modal.js +10 -12
  109. package/blocks/SimpleBtn/SimpleBtn.d.ts +2 -2
  110. package/blocks/SourceBtn/SourceBtn.d.ts +2 -2
  111. package/blocks/SourceBtn/SourceBtn.d.ts.map +1 -1
  112. package/blocks/SourceBtn/SourceBtn.js +0 -8
  113. package/blocks/Thumb/Thumb.d.ts +2 -2
  114. package/blocks/Thumb/Thumb.d.ts.map +1 -1
  115. package/blocks/Thumb/Thumb.js +2 -0
  116. package/blocks/UploadCtxProvider/EventEmitter.d.ts +17 -4
  117. package/blocks/UploadCtxProvider/EventEmitter.d.ts.map +1 -1
  118. package/blocks/UploadCtxProvider/EventEmitter.js +14 -2
  119. package/blocks/UploadList/UploadList.d.ts +2 -2
  120. package/blocks/UrlSource/UrlSource.js +3 -1
  121. package/blocks/themes/uc-basic/common.css +4 -0
  122. package/blocks/themes/uc-basic/index.css +0 -1
  123. package/blocks/themes/uc-basic/svg-sprite.d.ts +1 -1
  124. package/blocks/themes/uc-basic/svg-sprite.d.ts.map +1 -1
  125. package/blocks/themes/uc-basic/svg-sprite.js +1 -1
  126. package/env.d.ts +1 -1
  127. package/env.js +1 -1
  128. package/index.d.ts +1 -2
  129. package/index.js +1 -2
  130. package/index.ssr.d.ts +19 -69
  131. package/index.ssr.d.ts.map +1 -1
  132. package/index.ssr.js +44 -143
  133. package/locales/file-uploader/ar.d.ts +4 -0
  134. package/locales/file-uploader/ar.js +4 -0
  135. package/locales/file-uploader/az.d.ts +4 -0
  136. package/locales/file-uploader/az.js +5 -0
  137. package/locales/file-uploader/ca.d.ts +4 -0
  138. package/locales/file-uploader/ca.js +6 -0
  139. package/locales/file-uploader/cs.d.ts +4 -0
  140. package/locales/file-uploader/cs.js +6 -0
  141. package/locales/file-uploader/da.d.ts +4 -0
  142. package/locales/file-uploader/da.js +6 -0
  143. package/locales/file-uploader/de.d.ts +4 -0
  144. package/locales/file-uploader/de.js +6 -0
  145. package/locales/file-uploader/el.d.ts +4 -0
  146. package/locales/file-uploader/el.js +6 -0
  147. package/locales/file-uploader/en.d.ts +4 -3
  148. package/locales/file-uploader/en.js +4 -3
  149. package/locales/file-uploader/es.d.ts +4 -0
  150. package/locales/file-uploader/es.js +6 -0
  151. package/locales/file-uploader/et.d.ts +4 -0
  152. package/locales/file-uploader/et.js +6 -0
  153. package/locales/file-uploader/fi.d.ts +4 -0
  154. package/locales/file-uploader/fi.js +6 -0
  155. package/locales/file-uploader/fr.d.ts +4 -0
  156. package/locales/file-uploader/fr.js +6 -0
  157. package/locales/file-uploader/he.d.ts +4 -0
  158. package/locales/file-uploader/he.js +6 -0
  159. package/locales/file-uploader/hy.d.ts +4 -0
  160. package/locales/file-uploader/hy.js +5 -0
  161. package/locales/file-uploader/is.d.ts +4 -0
  162. package/locales/file-uploader/is.js +6 -0
  163. package/locales/file-uploader/it.d.ts +4 -0
  164. package/locales/file-uploader/it.js +6 -0
  165. package/locales/file-uploader/ja.d.ts +4 -0
  166. package/locales/file-uploader/ja.js +6 -0
  167. package/locales/file-uploader/ka.d.ts +4 -0
  168. package/locales/file-uploader/ka.js +6 -0
  169. package/locales/file-uploader/kk.d.ts +4 -0
  170. package/locales/file-uploader/kk.js +6 -0
  171. package/locales/file-uploader/ko.d.ts +4 -0
  172. package/locales/file-uploader/ko.js +6 -0
  173. package/locales/file-uploader/lv.d.ts +4 -0
  174. package/locales/file-uploader/lv.js +6 -0
  175. package/locales/file-uploader/nb.d.ts +4 -0
  176. package/locales/file-uploader/nb.js +6 -0
  177. package/locales/file-uploader/nl.d.ts +4 -0
  178. package/locales/file-uploader/nl.js +6 -0
  179. package/locales/file-uploader/pl.d.ts +4 -0
  180. package/locales/file-uploader/pl.js +6 -0
  181. package/locales/file-uploader/pt.d.ts +4 -0
  182. package/locales/file-uploader/pt.js +6 -0
  183. package/locales/file-uploader/ro.d.ts +4 -0
  184. package/locales/file-uploader/ro.js +6 -0
  185. package/locales/file-uploader/ru.d.ts +4 -0
  186. package/locales/file-uploader/ru.js +4 -0
  187. package/locales/file-uploader/sk.d.ts +4 -0
  188. package/locales/file-uploader/sk.js +6 -0
  189. package/locales/file-uploader/sr.d.ts +4 -0
  190. package/locales/file-uploader/sr.js +6 -0
  191. package/locales/file-uploader/sv.d.ts +4 -0
  192. package/locales/file-uploader/sv.js +6 -0
  193. package/locales/file-uploader/tr.d.ts +4 -0
  194. package/locales/file-uploader/tr.js +6 -0
  195. package/locales/file-uploader/uk.d.ts +4 -0
  196. package/locales/file-uploader/uk.js +6 -0
  197. package/locales/file-uploader/vi.d.ts +4 -0
  198. package/locales/file-uploader/vi.js +6 -0
  199. package/locales/file-uploader/zh-TW.d.ts +4 -0
  200. package/locales/file-uploader/zh-TW.js +6 -0
  201. package/locales/file-uploader/zh.d.ts +4 -0
  202. package/locales/file-uploader/zh.js +4 -0
  203. package/package.json +8 -8
  204. package/solutions/cloud-image-editor/CloudImageEditor.d.ts +35 -0
  205. package/solutions/cloud-image-editor/CloudImageEditor.d.ts.map +1 -1
  206. package/solutions/cloud-image-editor/CloudImageEditor.js +12 -0
  207. package/solutions/file-uploader/inline/FileUploaderInline.d.ts +3 -2
  208. package/solutions/file-uploader/inline/FileUploaderInline.d.ts.map +1 -1
  209. package/solutions/file-uploader/inline/FileUploaderInline.js +4 -0
  210. package/solutions/file-uploader/minimal/FileUploaderMinimal.d.ts +11 -10
  211. package/solutions/file-uploader/minimal/FileUploaderMinimal.d.ts.map +1 -1
  212. package/solutions/file-uploader/minimal/FileUploaderMinimal.js +9 -9
  213. package/solutions/file-uploader/regular/FileUploaderRegular.d.ts +3 -2
  214. package/solutions/file-uploader/regular/FileUploaderRegular.d.ts.map +1 -1
  215. package/solutions/file-uploader/regular/FileUploaderRegular.js +4 -4
  216. package/types/events.d.ts +1 -1
  217. package/types/exported.d.ts +59 -52
  218. package/types/jsx.d.ts +2 -0
  219. package/utils/isPromiseLike.d.ts +2 -0
  220. package/utils/isPromiseLike.d.ts.map +1 -0
  221. package/utils/isPromiseLike.js +12 -0
  222. package/utils/isPromiseLike.test.d.ts +2 -0
  223. package/utils/isPromiseLike.test.d.ts.map +1 -0
  224. package/utils/isPromiseLike.test.js +20 -0
  225. package/utils/parseCdnUrl.d.ts.map +1 -1
  226. package/utils/parseCdnUrl.js +4 -1
  227. package/utils/parseCdnUrl.test.js +13 -0
  228. package/utils/validators/collection/validateCollectionUploadError.d.ts +2 -2
  229. package/utils/validators/collection/validateCollectionUploadError.d.ts.map +1 -1
  230. package/utils/validators/collection/validateCollectionUploadError.js +1 -1
  231. package/utils/validators/collection/validateMultiple.d.ts +2 -2
  232. package/utils/validators/collection/validateMultiple.d.ts.map +1 -1
  233. package/utils/validators/collection/validateMultiple.js +1 -1
  234. package/utils/validators/file/validateFileType.d.ts +2 -2
  235. package/utils/validators/file/validateFileType.d.ts.map +1 -1
  236. package/utils/validators/file/validateFileType.js +1 -1
  237. package/utils/validators/file/validateIsImage.d.ts +2 -2
  238. package/utils/validators/file/validateIsImage.d.ts.map +1 -1
  239. package/utils/validators/file/validateIsImage.js +1 -1
  240. package/utils/validators/file/validateMaxSizeLimit.d.ts +2 -2
  241. package/utils/validators/file/validateMaxSizeLimit.d.ts.map +1 -1
  242. package/utils/validators/file/validateMaxSizeLimit.js +1 -1
  243. package/utils/validators/file/validateUploadError.d.ts +2 -2
  244. package/utils/validators/file/validateUploadError.d.ts.map +1 -1
  245. package/utils/validators/file/validateUploadError.js +1 -1
  246. package/web/file-uploader.iife.min.js +5 -5
  247. package/web/file-uploader.min.js +5 -5
  248. package/web/uc-basic.min.css +1 -1
  249. package/web/uc-cloud-image-editor.min.css +1 -1
  250. package/web/uc-cloud-image-editor.min.js +5 -5
  251. package/web/uc-file-uploader-inline.min.css +1 -1
  252. package/web/uc-file-uploader-inline.min.js +5 -5
  253. package/web/uc-file-uploader-minimal.min.css +1 -1
  254. package/web/uc-file-uploader-minimal.min.js +5 -5
  255. package/web/uc-file-uploader-regular.min.css +1 -1
  256. package/web/uc-file-uploader-regular.min.js +5 -5
  257. package/web/uc-img.min.js +2 -2
  258. package/abstract/SecureUploadsManager.d.ts +0 -22
  259. package/abstract/ValidationManager.d.ts.map +0 -1
  260. package/abstract/a11y.d.ts.map +0 -1
  261. package/blocks/AiGenerateSource/AIGenerateSource.d.ts +0 -47
  262. package/blocks/AiGenerateSource/AIGenerateSource.d.ts.map +0 -1
  263. package/blocks/AiGenerateSource/AIGenerateSource.js +0 -180
  264. package/blocks/AiGenerateSource/ai-generate-source.css +0 -58
@@ -1,8 +1,8 @@
1
1
  // @ts-check
2
2
  import { debounce } from '../../utils/debounce.js';
3
- import { ActivityBlock } from '../../../abstract/ActivityBlock.js';
4
3
  import { Block } from '../../../abstract/Block.js';
5
4
  import { EditorCropButtonControl } from './EditorCropButtonControl.js';
5
+ import { EditorAspectRatioButtonControl, EditorFreeformButtonControl } from './EditorAspectRatioButtonControl.js';
6
6
  import { EditorFilterControl } from './EditorFilterControl.js';
7
7
  import { EditorOperationControl } from './EditorOperationControl.js';
8
8
  import { FAKE_ORIGINAL_FILTER } from './EditorSlider.js';
@@ -16,6 +16,7 @@ import {
16
16
  TabId,
17
17
  } from './toolbar-constants.js';
18
18
  import { viewerImageSrc } from './util.js';
19
+ import { parseFilterValue } from './utils/parseFilterValue.js';
19
20
 
20
21
  /** @param {String} id */
21
22
  function renderTabToggle(id) {
@@ -65,9 +66,12 @@ export class EditorToolbar extends Block {
65
66
  this.init$ = {
66
67
  ...this.init$,
67
68
  '*sliderEl': null,
69
+ '*listAspectRatioEl': null,
68
70
  /** @type {import('./types.js').LoadingOperations} */
69
71
  '*loadingOperations': new Map(),
70
72
  '*showSlider': false,
73
+ '*showListAspectRatio': false,
74
+ hideSliderOrList: false,
71
75
  '*currentFilter': FAKE_ORIGINAL_FILTER,
72
76
  '*currentOperation': null,
73
77
  showLoader: false,
@@ -82,11 +86,9 @@ export class EditorToolbar extends Block {
82
86
  'presence.tabContent.crop': false,
83
87
  'presence.tabContent.tuning': false,
84
88
  'presence.tabContent.filters': false,
85
- 'presence.tabContent.ai': false,
86
89
  'presence.tabToggle.crop': true,
87
90
  'presence.tabToggle.tuning': true,
88
91
  'presence.tabToggle.filters': true,
89
- 'presence.tabToggle.ai': true,
90
92
  'presence.subTopToolbarStyles': {
91
93
  hidden: 'uc-sub-toolbar--top-hidden',
92
94
  visible: 'uc-sub-toolbar--visible',
@@ -107,18 +109,36 @@ export class EditorToolbar extends Block {
107
109
  hidden: 'uc-tab-toggles--hidden',
108
110
  visible: 'uc-tab-toggles--visible',
109
111
  },
110
- 'on.cancel': () => {
112
+ /** @param {MouseEvent} e */
113
+ 'on.cancel': (e) => {
114
+ this.telemetryManager.sendEventCloudImageEditor(e, this.$['*tabId'], {
115
+ action: 'cancel',
116
+ });
117
+
111
118
  this._cancelPreload?.();
112
119
  this.$['*on.cancel']();
113
120
  },
114
- 'on.apply': () => {
121
+ /** @param {MouseEvent} e */
122
+ 'on.apply': (e) => {
123
+ this.telemetryManager.sendEventCloudImageEditor(e, this.$['*tabId'], {
124
+ action: 'apply',
125
+ });
115
126
  this.$['*on.apply'](this.$['*editorTransformations']);
116
127
  },
117
- 'on.applySlider': () => {
128
+ /** @param {MouseEvent} e */
129
+ 'on.applySlider': (e) => {
130
+ this.telemetryManager.sendEventCloudImageEditor(e, this.$['*tabId'], {
131
+ action: 'apply-slider',
132
+ operation: parseFilterValue(this.$['*operationTooltip']),
133
+ });
118
134
  this.ref['slider-el'].apply();
119
135
  this._onSliderClose();
120
136
  },
121
- 'on.cancelSlider': () => {
137
+ /** @param {MouseEvent} e */
138
+ 'on.cancelSlider': (e) => {
139
+ this.telemetryManager.sendEventCloudImageEditor(e, this.$['*tabId'], {
140
+ action: 'cancel-slider',
141
+ });
122
142
  this.ref['slider-el'].cancel();
123
143
  this._onSliderClose();
124
144
  },
@@ -126,6 +146,7 @@ export class EditorToolbar extends Block {
126
146
  'on.clickTab': (e) => {
127
147
  const id = /** @type {HTMLElement} */ (e.currentTarget).getAttribute('data-id');
128
148
  if (id) {
149
+ this.telemetryManager.sendEventCloudImageEditor(e, id);
129
150
  this._activateTab(id, { fromViewer: false });
130
151
  }
131
152
  },
@@ -133,7 +154,6 @@ export class EditorToolbar extends Block {
133
154
  [`tab_${TabId.TUNING}`]: `tab_${TabId.TUNING}`,
134
155
  [`tab_${TabId.CROP}`]: `tab_${TabId.CROP}`,
135
156
  [`tab_${TabId.FILTERS}`]: `tab_${TabId.FILTERS}`,
136
- [`tab_${TabId.AI}`]: `tab_${TabId.AI}`,
137
157
  cancel: 'cancel',
138
158
  apply: 'apply',
139
159
  'a11y-editor-tab-filters': 'a11y-editor-tab-filters',
@@ -149,6 +169,11 @@ export class EditorToolbar extends Block {
149
169
  /** @private */
150
170
  _onSliderClose() {
151
171
  this.$['*showSlider'] = false;
172
+
173
+ if (this.$['*tabId'] === TabId.CROP) {
174
+ this.$['*showListAspectRatio'] = false;
175
+ }
176
+
152
177
  if (this.$['*tabId'] === TabId.TUNING) {
153
178
  this.ref['tooltip-el'].classList.toggle('uc-info-tooltip_visible', false);
154
179
  }
@@ -187,6 +212,26 @@ export class EditorToolbar extends Block {
187
212
  return el;
188
213
  }
189
214
 
215
+ /**
216
+ * @private
217
+ * @param {import('./types.js').CropAspectRatio} config
218
+ */
219
+ _createAspectRatioConrol(config) {
220
+ const el = new EditorAspectRatioButtonControl();
221
+ // @ts-expect-error TODO: fix
222
+ el.aspectRatio = config;
223
+ return el;
224
+ }
225
+
226
+ _createFreeformConrol() {
227
+ const el = new EditorFreeformButtonControl();
228
+ return el;
229
+ }
230
+
231
+ _clearListAspectRatio() {
232
+ this.$['*listAspectRatioEl'].innerHTML = '';
233
+ }
234
+
190
235
  /**
191
236
  * @private
192
237
  * @param {String} tabId
@@ -195,7 +240,27 @@ export class EditorToolbar extends Block {
195
240
  let listEl = this.ref[`controls-list-${tabId}`];
196
241
  let fr = document.createDocumentFragment();
197
242
 
243
+ this._clearListAspectRatio();
244
+
198
245
  if (tabId === TabId.CROP) {
246
+ const hasFreeformAspectRatio = this.$['*cropPresetList'].length >= 3;
247
+
248
+ if (hasFreeformAspectRatio) {
249
+ const el = this._createFreeformConrol();
250
+ fr.appendChild(el);
251
+ }
252
+
253
+ this.$['*cropPresetList'].forEach(
254
+ /** @param {import('./types.js').CropAspectRatio} it */ (it) => {
255
+ let el = this._createAspectRatioConrol(it);
256
+ fr.appendChild(el);
257
+
258
+ if (hasFreeformAspectRatio) {
259
+ this.$['*listAspectRatioEl'].appendChild(el);
260
+ }
261
+ },
262
+ );
263
+
199
264
  this.$.cropOperations.forEach(
200
265
  /** @param {string} operation */ (operation) => {
201
266
  let el = this._createToggleControl(operation);
@@ -229,11 +294,6 @@ export class EditorToolbar extends Block {
229
294
  listEl.appendChild(fr);
230
295
  }
231
296
 
232
- redirectToAiGenerate() {
233
- this.$['*currentActivity'] = ActivityBlock.activities.AI_GENERATE;
234
- this.modalManager.open(ActivityBlock.activities.AI_GENERATE);
235
- }
236
-
237
297
  /**
238
298
  * @private
239
299
  * @param {String} id
@@ -242,13 +302,6 @@ export class EditorToolbar extends Block {
242
302
  _activateTab(id, { fromViewer }) {
243
303
  this.$['*tabId'] = id;
244
304
 
245
- if (id === TabId.AI) {
246
- console.log('Redirecting to AI generation...');
247
-
248
- this.redirectToAiGenerate();
249
- return;
250
- }
251
-
252
305
  if (id === TabId.CROP) {
253
306
  this.$['*faderEl'].deactivate();
254
307
  this.$['*cropperEl'].activate(this.$['*imageSize'], { fromViewer });
@@ -343,6 +396,7 @@ export class EditorToolbar extends Block {
343
396
  super.initCallback();
344
397
 
345
398
  this.$['*sliderEl'] = this.ref['slider-el'];
399
+ this.$['*listAspectRatioEl'] = this.ref['list-el'];
346
400
 
347
401
  this.sub('*imageSize', (imageSize) => {
348
402
  if (imageSize) {
@@ -401,6 +455,14 @@ export class EditorToolbar extends Block {
401
455
  this.sub('*showSlider', (showSlider) => {
402
456
  this.$['presence.subToolbar'] = showSlider;
403
457
  this.$['presence.mainToolbar'] = !showSlider;
458
+
459
+ this.$.hideSliderOrList = true;
460
+ });
461
+
462
+ this.sub('*showListAspectRatio', (show) => {
463
+ this.$['presence.subToolbar'] = show;
464
+ this.$['presence.mainToolbar'] = !show;
465
+ this.$.hideSliderOrList = false;
404
466
  });
405
467
 
406
468
  this.sub('*tabList', (tabList) => {
@@ -421,6 +483,7 @@ export class EditorToolbar extends Block {
421
483
 
422
484
  destroyCallback() {
423
485
  this.$['*showSlider'] = false;
486
+ this.$['*showListAspectRatio'] = false;
424
487
  }
425
488
  }
426
489
 
@@ -455,9 +518,13 @@ EditorToolbar.template = /* HTML */ `
455
518
  class="uc-sub-toolbar"
456
519
  set="visible: presence.subToolbar; styles: presence.subBottomToolbarStyles"
457
520
  >
458
- <div class="uc-slider">
521
+ <div class="uc-slider" set="@hidden:!hideSliderOrList">
459
522
  <uc-editor-slider ref="slider-el"></uc-editor-slider>
460
523
  </div>
524
+
525
+ <div set="@hidden:hideSliderOrList" class="uc-list-aspect-ratio-container">
526
+ <div class="uc-list-aspect-ratio" ref="list-el"></div>
527
+ </div>
461
528
  <div class="uc-controls-row">
462
529
  <uc-btn-ui theme="secondary" set="onclick: on.cancelSlider" l10n="@text:cancel"> </uc-btn-ui>
463
530
  <uc-btn-ui theme="primary" set="onclick: on.applySlider" l10n="@text:apply"> </uc-btn-ui>
@@ -301,34 +301,36 @@ uc-crop-frame > .uc-thumb {
301
301
  opacity var(--transition-duration-3);
302
302
  }
303
303
 
304
- uc-crop-frame > .uc-thumb--visible {
304
+ uc-crop-frame .uc-thumb--visible {
305
305
  opacity: 1;
306
306
  pointer-events: auto;
307
307
  }
308
308
 
309
- uc-crop-frame > .uc-thumb--hidden {
309
+ uc-crop-frame .uc-thumb--hidden {
310
310
  opacity: 0;
311
311
  pointer-events: none;
312
312
  }
313
313
 
314
- uc-crop-frame > .uc-guides {
314
+ uc-crop-frame .uc-guides {
315
315
  transition: var(--transition-duration-3);
316
316
  }
317
317
 
318
- uc-crop-frame > .uc-guides--hidden {
318
+ uc-crop-frame .uc-guides--hidden {
319
319
  opacity: 0;
320
320
  }
321
321
 
322
- uc-crop-frame > .uc-guides--semi-hidden {
322
+ uc-crop-frame .uc-guides--semi-hidden {
323
323
  opacity: 0.2;
324
324
  }
325
325
 
326
- uc-crop-frame > .uc-guides--visible {
326
+ uc-crop-frame .uc-guides--visible {
327
327
  opacity: 1;
328
328
  }
329
329
 
330
330
  uc-editor-button-control,
331
331
  uc-editor-crop-button-control,
332
+ uc-editor-aspect-ratio-button-control,
333
+ uc-editor-freeform-button-control,
332
334
  uc-editor-filter-control,
333
335
  uc-editor-operation-control {
334
336
  --l-base-min-width: var(--uc-button-size);
@@ -356,6 +358,8 @@ uc-editor-operation-control {
356
358
 
357
359
  uc-editor-button-control > button,
358
360
  uc-editor-crop-button-control > button,
361
+ uc-editor-aspect-ratio-button-control > button,
362
+ uc-editor-freeform-button-control > button,
359
363
  uc-editor-filter-control > button,
360
364
  uc-editor-operation-control > button {
361
365
  all: unset;
@@ -371,7 +375,23 @@ uc-editor-operation-control > button {
371
375
  transition: var(--l-width-transition);
372
376
  }
373
377
 
374
- :where(uc-editor-button-control, uc-editor-crop-button-control, uc-editor-filter-control, uc-editor-operation-control)
378
+ uc-editor-freeform-button-control > button {
379
+ grid-template-columns: auto var(--l-base-min-width);
380
+ }
381
+
382
+ uc-editor-freeform-button-control > button > uc-icon {
383
+ margin-left: var(--cldtr-gap-mid-1);
384
+ width: 10px;
385
+ }
386
+
387
+ :where(
388
+ uc-editor-button-control,
389
+ uc-editor-crop-button-control,
390
+ uc-editor-aspect-ratio-button-control,
391
+ uc-editor-freeform-button-control,
392
+ uc-editor-filter-control,
393
+ uc-editor-operation-control
394
+ )
375
395
  > uc-icon
376
396
  > svg {
377
397
  width: var(--size-icon);
@@ -386,6 +406,8 @@ uc-editor-filter-control > uc-icon.uc-original-icon > svg {
386
406
  uc-editor-button-control.uc-active,
387
407
  uc-editor-operation-control.uc-active,
388
408
  uc-editor-crop-button-control.uc-active,
409
+ uc-editor-aspect-ratio-button-control.uc-active,
410
+ uc-editor-freeform-button-control.uc-active,
389
411
  uc-editor-filter-control.uc-active {
390
412
  --idle-color-rgb: var(--uc-primary-foreground);
391
413
  --idle-background: var(--uc-primary);
@@ -406,6 +428,8 @@ uc-editor-filter-control.uc-active .uc-preview {
406
428
  uc-editor-button-control.uc-not_active,
407
429
  uc-editor-operation-control.uc-not_active,
408
430
  uc-editor-crop-button-control.uc-not_active,
431
+ uc-editor-aspect-ratio-button-control.uc-not_active,
432
+ uc-editor-freeform-button-control.uc-not_active,
409
433
  uc-editor-filter-control.uc-not_active {
410
434
  --idle-color-rgb: var(--uc-secondary-foreground);
411
435
  }
@@ -413,6 +437,8 @@ uc-editor-filter-control.uc-not_active {
413
437
  :where(.uc-contrast) uc-editor-button-control.uc-not_active,
414
438
  :where(.uc-contrast) uc-editor-operation-control.uc-not_active,
415
439
  :where(.uc-contrast) uc-editor-crop-button-control.uc-not_active,
440
+ :where(.uc-contrast) uc-editor-freeform-button-control.uc-not_active,
441
+ :where(.uc-contrast) uc-editor-aspect-ratio-button-control.uc-not_active,
416
442
  :where(.uc-contrast) uc-editor-filter-control.uc-not_active {
417
443
  --idle-background: transparent;
418
444
  --hover-background: var(--uc-secondary);
@@ -424,6 +450,8 @@ uc-editor-filter-control.uc-not_active {
424
450
  uc-editor-button-control > button::before,
425
451
  uc-editor-operation-control > button::before,
426
452
  uc-editor-crop-button-control > button::before,
453
+ uc-editor-freeform-button-control > button::before,
454
+ uc-editor-aspect-ratio-button-control > button::before,
427
455
  uc-editor-filter-control > button::before {
428
456
  position: absolute;
429
457
  content: '';
@@ -440,6 +468,8 @@ uc-editor-filter-control > button::before {
440
468
  uc-editor-button-control > button .uc-title,
441
469
  uc-editor-operation-control > button .uc-title,
442
470
  uc-editor-crop-button-control > button .uc-title,
471
+ uc-editor-aspect-ratio-button-control > button .uc-title,
472
+ uc-editor-freeform-button-control > button .uc-title,
443
473
  uc-editor-filter-control > button .uc-title {
444
474
  padding-right: var(--cldtr-gap-mid-1);
445
475
  font-size: 0.7em;
@@ -447,9 +477,16 @@ uc-editor-filter-control > button .uc-title {
447
477
  text-transform: uppercase;
448
478
  }
449
479
 
480
+ uc-editor-freeform-button-control > button .uc-title {
481
+ padding-left: var(--cldtr-gap-mid-1);
482
+ padding-right: 0;
483
+ }
484
+
450
485
  uc-editor-button-control > button uc-icon,
451
486
  uc-editor-operation-control > button uc-icon,
452
487
  uc-editor-crop-button-control > button uc-icon,
488
+ uc-editor-aspect-ratio-button-control > button uc-icon,
489
+ uc-editor-freeform-button-control > button uc-icon,
453
490
  uc-editor-filter-control > button uc-icon {
454
491
  pointer-events: none;
455
492
  }
@@ -643,6 +680,15 @@ uc-editor-toolbar > .uc-toolbar-container > .uc-sub-toolbar {
643
680
  visibility var(--transition-duration-3) ease-in-out;
644
681
  }
645
682
 
683
+ .uc-sub-toolbar > .uc-list-aspect-ratio-container > .uc-list-aspect-ratio {
684
+ display: grid;
685
+ grid-auto-flow: column;
686
+ justify-content: center;
687
+ align-items: center;
688
+ gap: 6px;
689
+ height: var(--size-panel-heading);
690
+ }
691
+
646
692
  uc-editor-toolbar > .uc-toolbar-container > .uc-sub-toolbar.uc-sub-toolbar--visible {
647
693
  transform: translateY(0px);
648
694
  opacity: 1;
@@ -1195,3 +1241,19 @@ uc-presence-toggle.uc-initial {
1195
1241
  [uc-cloud-image-editor] .uc-cloud-mask {
1196
1242
  pointer-events: none;
1197
1243
  }
1244
+
1245
+ [uc-aspect-ratio-freeform] button {
1246
+ display: flex;
1247
+ }
1248
+
1249
+ [uc-aspect-ratio-freeform] uc-icon {
1250
+ display: none;
1251
+ }
1252
+
1253
+ [uc-aspect-ratio-freeform] .uc-title {
1254
+ padding-left: var(--cldtr-gap-mid-1);
1255
+ }
1256
+
1257
+ :where(uc-editor-freeform-button-control, uc-editor-aspect-ratio-button-control:last-of-type) {
1258
+ margin-right: calc(3 * var(--cldtr-gap-mid-1));
1259
+ }
@@ -12,4 +12,5 @@ export { BtnUi } from "./elements/button/BtnUi.js";
12
12
  export { LineLoaderUi } from "./elements/line-loader/LineLoaderUi.js";
13
13
  export { PresenceToggle } from "./elements/presence-toggle/PresenceToggle.js";
14
14
  export { SliderUi } from "./elements/slider/SliderUi.js";
15
+ export { EditorAspectRatioButtonControl, EditorFreeformButtonControl } from "./EditorAspectRatioButtonControl.js";
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1,6 +1,7 @@
1
1
  export { CloudImageEditorBlock } from './CloudImageEditorBlock.js';
2
2
  export { CropFrame } from './CropFrame.js';
3
3
  export { EditorCropButtonControl } from './EditorCropButtonControl.js';
4
+ export { EditorAspectRatioButtonControl, EditorFreeformButtonControl } from './EditorAspectRatioButtonControl.js';
4
5
  export { EditorFilterControl } from './EditorFilterControl.js';
5
6
  export { EditorOperationControl } from './EditorOperationControl.js';
6
7
  export { EditorImageCropper } from './EditorImageCropper.js';
@@ -1,2 +1,3 @@
1
- export function parseCropPreset(cropPreset: import("../../../../types/exported.d.ts").ConfigType["cropPreset"]): import("../types.js").CropAspectRatio[] | undefined;
1
+ export function parseCropPreset(cropPreset: import("../../../../types/exported.d.ts").ConfigType["cropPreset"]): import("../types.js").CropAspectRatio[];
2
+ export function getClosestAspectRatio(width: number, height: number, ratios: import("../types.js").CropPresetList, tolerance?: number): import("../types.js").CropAspectRatio | null;
2
3
  //# sourceMappingURL=parseCropPreset.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parseCropPreset.d.ts","sourceRoot":"","sources":["parseCropPreset.js"],"names":[],"mappings":"AAGO,4CADK,OAAO,iCAAiC,EAAE,UAAU,CAAC,YAAY,CAAC,uDAW7E"}
1
+ {"version":3,"file":"parseCropPreset.d.ts","sourceRoot":"","sources":["parseCropPreset.js"],"names":[],"mappings":"AAOO,4CADK,OAAO,iCAAiC,EAAE,UAAU,CAAC,YAAY,CAAC,2CAmC7E;AASM,6CANI,MAAM,UACN,MAAM,UACN,OAAO,aAAa,EAAE,cAAc,cACpC,MAAM,GACJ,OAAO,aAAa,EAAE,eAAe,GAAG,IAAI,CA+BxD"}
@@ -1,14 +1,80 @@
1
1
  // @ts-check
2
+ import { UID } from '@symbiotejs/symbiote';
3
+ import { stringToArray } from '../../../../utils/stringToArray.js';
4
+
5
+ const EXCLUDED_TYPES = ['free'];
2
6
 
3
7
  /** @param {import('../../../../types/exported.d.ts').ConfigType['cropPreset']} cropPreset */
4
8
  export const parseCropPreset = (cropPreset) => {
5
- if (!cropPreset) return [];
6
- const [w, h] = cropPreset.split(':').map(Number);
7
- if (!Number.isFinite(w) || !Number.isFinite(h)) {
8
- console.error(`Invalid crop preset: ${cropPreset}`);
9
- return;
9
+ const items = stringToArray(cropPreset);
10
+ if (!items?.length) return [];
11
+
12
+ /** @type {import('../types.js').CropAspectRatio[]} */
13
+ const result = [];
14
+ for (let i = 0; i < items.length; i++) {
15
+ const raw = items[i].trim();
16
+ if (!raw) continue;
17
+
18
+ const sep = raw.indexOf(':');
19
+ if (sep === -1 && !EXCLUDED_TYPES.includes(raw)) {
20
+ console.warn(`Invalid crop preset: ${raw}`);
21
+ continue;
22
+ }
23
+
24
+ const w = Number(raw.slice(0, sep));
25
+ const h = Number(raw.slice(sep + 1));
26
+
27
+ if ((!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) && !EXCLUDED_TYPES.includes(raw)) {
28
+ console.warn(`Invalid crop preset: ${raw}`);
29
+ continue;
30
+ }
31
+
32
+ result.push({
33
+ id: UID.generate(),
34
+ type: 'aspect-ratio',
35
+ width: EXCLUDED_TYPES.includes(raw) ? 0 : w,
36
+ height: EXCLUDED_TYPES.includes(raw) ? 0 : h,
37
+ hasFreeform: EXCLUDED_TYPES.includes(raw),
38
+ });
39
+ }
40
+
41
+ return result;
42
+ };
43
+
44
+ /**
45
+ * @param {number} width
46
+ * @param {number} height
47
+ * @param {import('../types.js').CropPresetList} ratios
48
+ * @param {number} tolerance
49
+ * @returns {import('../types.js').CropAspectRatio | null}
50
+ */
51
+ export const getClosestAspectRatio = (width, height, ratios, tolerance = 0.1) => {
52
+ const inputRatio = width / height;
53
+
54
+ let closest = null;
55
+ let minDiff = Infinity;
56
+
57
+ for (const r of ratios) {
58
+ const [w, h] = [r.width, r.height];
59
+ const ratio = w / h;
60
+
61
+ const diff = Math.abs(inputRatio - ratio);
62
+
63
+ if (diff < minDiff) {
64
+ minDiff = diff;
65
+ closest = r;
66
+ }
10
67
  }
11
- /** @type {import('../types.js').CropAspectRatio} */
12
- const aspectRatio = { type: 'aspect-ratio', width: w, height: h };
13
- return [aspectRatio];
68
+
69
+ if (closest) {
70
+ const [cw, ch] = [closest.width, closest.height];
71
+ const closestRatio = cw / ch;
72
+
73
+ const relDiff = Math.abs(inputRatio - closestRatio) / closestRatio;
74
+ if (relDiff > tolerance) {
75
+ return null;
76
+ }
77
+ }
78
+
79
+ return closest;
14
80
  };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=parseCropPreset.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseCropPreset.test.d.ts","sourceRoot":"","sources":["parseCropPreset.test.js"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import { expect } from '@esm-bundle/chai';
2
+ import { fake } from 'sinon';
3
+ import { UID } from '@symbiotejs/symbiote';
4
+ import { parseCropPreset, getClosestAspectRatio } from './parseCropPreset';
5
+
6
+ describe('parseCropPreset', () => {
7
+ it('should parse crop presets correctly', () => {
8
+ const uniqueIds = 4;
9
+ let uidCallCount = 0;
10
+ UID.generate = fake(() => {
11
+ const id = `id-${(uidCallCount % uniqueIds) + 1}`;
12
+ uidCallCount += 1;
13
+ return id;
14
+ });
15
+
16
+ const input = '16:9, 3:4, 4:3, 1:1';
17
+ const uuid = () => UID.generate();
18
+ const expected = [
19
+ { id: uuid(), type: 'aspect-ratio', width: 16, height: 9, hasFreeform: false },
20
+ { id: uuid(), type: 'aspect-ratio', width: 3, height: 4, hasFreeform: false },
21
+ { id: uuid(), type: 'aspect-ratio', width: 4, height: 3, hasFreeform: false },
22
+ { id: uuid(), type: 'aspect-ratio', width: 1, height: 1, hasFreeform: false },
23
+ ];
24
+ const list = parseCropPreset(input);
25
+ expect(list).to.deep.equal(expected);
26
+
27
+ expect(getClosestAspectRatio(400, 500, list, 0.1)).to.deep.equal({
28
+ hasFreeform: false,
29
+ height: 4,
30
+ id: 'id-2',
31
+ type: 'aspect-ratio',
32
+ width: 3,
33
+ });
34
+ });
35
+ });
@@ -9,9 +9,9 @@ export function initState(fnCtx: import("./CloudImageEditorBlock.js").CloudImage
9
9
  '*imageSize': null;
10
10
  /** @type {import('./types.js').Transformations} */
11
11
  '*editorTransformations': import("./types.js").Transformations;
12
- /** @type {import('./types.js').CropPresetList} */
13
12
  '*cropPresetList': import("./types.js").CropPresetList;
14
- '*tabList': ("crop" | "tuning" | "filters" | "ai")[];
13
+ '*currentAspectRatio': null;
14
+ '*tabList': ("crop" | "tuning" | "filters")[];
15
15
  '*tabId': "crop";
16
16
  entry: null;
17
17
  extension: null;
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["state.js"],"names":[],"mappings":"AAQA,gFAAgF;AAChF,iCADY,OAAO,4BAA4B,EAAE,qBAAqB;;;;;;;;IAUlE,mDAAmD;8BAAxC,OAAO,YAAY,EAAE,eAAe;IAE/C,kDAAkD;uBAAvC,OAAO,YAAY,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;IAmC9C,oEAAoE;mCAAxD,OAAO,YAAY,EAAE,eAAe;;EAoCnD"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["state.js"],"names":[],"mappings":"AAQA,gFAAgF;AAChF,iCADY,OAAO,4BAA4B,EAAE,qBAAqB;;;;;;;;IAUlE,mDAAmD;8BAAxC,OAAO,YAAY,EAAE,eAAe;uBAEjB,OAAO,YAAY,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;IAmCjE,oEAAoE;mCAAxD,OAAO,YAAY,EAAE,eAAe;;EAoCnD"}
@@ -18,8 +18,8 @@ export function initState(fnCtx) {
18
18
  '*imageSize': null,
19
19
  /** @type {import('./types.js').Transformations} */
20
20
  '*editorTransformations': {},
21
- /** @type {import('./types.js').CropPresetList} */
22
- '*cropPresetList': [],
21
+ '*cropPresetList': /** @type {import('./types.js').CropPresetList} */ ([]),
22
+ '*currentAspectRatio': /** @type {import('./types.js').CropPresetList[0] | null} */ null,
23
23
  '*tabList': ALL_TABS,
24
24
  '*tabId': TabId.CROP,
25
25