@shelamkoff/rector 1.0.1 → 1.0.2

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 (54) hide show
  1. package/README.md +25 -24
  2. package/dist/core/clipboard/Clipboard.d.ts +2 -0
  3. package/dist/core/clipboard/Clipboard.js +52 -24
  4. package/dist/core/index.js +195 -194
  5. package/dist/core/locale/en.d.ts +1 -0
  6. package/dist/core/locale/en.js +1 -0
  7. package/dist/core/locale/ru.d.ts +1 -0
  8. package/dist/core/locale/ru.js +1 -0
  9. package/dist/core/themes/light.css +1 -1
  10. package/dist/core/themes/variables.css +72 -10
  11. package/dist/locale/en.d.ts +41 -0
  12. package/dist/locale/ru.d.ts +41 -0
  13. package/dist/plugins/attaches/attaches.css +16 -14
  14. package/dist/plugins/attaches/index.js +997 -920
  15. package/dist/plugins/attaches/locale/en.d.ts +9 -0
  16. package/dist/plugins/attaches/locale/en.js +11 -2
  17. package/dist/plugins/attaches/locale/ru.d.ts +9 -0
  18. package/dist/plugins/attaches/locale/ru.js +11 -2
  19. package/dist/plugins/carousel/carousel.css +213 -49
  20. package/dist/plugins/carousel/index.js +918 -858
  21. package/dist/plugins/carousel/locale/en.d.ts +15 -0
  22. package/dist/plugins/carousel/locale/en.js +18 -3
  23. package/dist/plugins/carousel/locale/ru.d.ts +15 -0
  24. package/dist/plugins/carousel/locale/ru.js +18 -3
  25. package/dist/plugins/gallery/gallery.css +6 -1
  26. package/dist/plugins/gallery/index.js +375 -354
  27. package/dist/plugins/gallery/locale/en.d.ts +8 -0
  28. package/dist/plugins/gallery/locale/en.js +11 -3
  29. package/dist/plugins/gallery/locale/ru.d.ts +8 -0
  30. package/dist/plugins/gallery/locale/ru.js +11 -3
  31. package/dist/plugins/gallery/view-empty.d.ts +2 -0
  32. package/dist/plugins/gallery/view-empty.js +21 -15
  33. package/dist/plugins/gallery/view-filled.d.ts +2 -2
  34. package/dist/plugins/gallery/view-filled.js +61 -56
  35. package/dist/plugins/image/image.css +7 -2
  36. package/dist/plugins/image/index.js +365 -345
  37. package/dist/plugins/image/locale/en.d.ts +8 -0
  38. package/dist/plugins/image/locale/en.js +11 -3
  39. package/dist/plugins/image/locale/ru.d.ts +8 -0
  40. package/dist/plugins/image/locale/ru.js +11 -3
  41. package/dist/plugins/image/view-empty.d.ts +2 -0
  42. package/dist/plugins/image/view-empty.js +21 -15
  43. package/dist/plugins/image/view-filled.d.ts +2 -2
  44. package/dist/plugins/image/view-filled.js +77 -72
  45. package/dist/plugins/shared/dropzone.d.ts +6 -0
  46. package/dist/plugins/shared/dropzone.js +47 -36
  47. package/dist/plugins/shared/layer.d.ts +13 -0
  48. package/dist/plugins/shared/layer.js +45 -0
  49. package/dist/plugins/shared/sourceEditor.css +165 -0
  50. package/dist/plugins/shared/sourceEditor.d.ts +97 -0
  51. package/dist/plugins/shared/sourceEditor.js +260 -0
  52. package/dist/renderer/renderers/carousel/index.js +24 -23
  53. package/dist/renderer/renderers/carousel/styles.css +8 -2
  54. package/package.json +32 -32
@@ -6,6 +6,14 @@ declare const _default: {
6
6
  'plugin.gallery.dropzone': string;
7
7
  'plugin.gallery.dropzoneUpload': string;
8
8
  'plugin.gallery.dropzoneText': string;
9
+ 'plugin.gallery.dropzoneUrlPrefix': string;
10
+ 'plugin.gallery.dropzoneUrl': string;
11
+ 'plugin.gallery.urlEditorTitle': string;
12
+ 'plugin.gallery.urlEditorLabel': string;
13
+ 'plugin.gallery.urlEditorPlaceholder': string;
14
+ 'plugin.gallery.sourceSubmit': string;
15
+ 'plugin.gallery.sourceCancel': string;
16
+ 'plugin.gallery.invalidUrl': string;
9
17
  'plugin.gallery.addMore': string;
10
18
  'plugin.gallery.delete': string;
11
19
  'plugin.gallery.deleteAll': string;
@@ -6,6 +6,14 @@ export default {
6
6
  'plugin.gallery.dropzone': 'or drag and drop files here',
7
7
  'plugin.gallery.dropzoneUpload': 'Upload',
8
8
  'plugin.gallery.dropzoneText': 'images from your device or drag and drop them here',
9
+ 'plugin.gallery.dropzoneUrlPrefix': 'or',
10
+ 'plugin.gallery.dropzoneUrl': 'insert by URL',
11
+ 'plugin.gallery.urlEditorTitle': 'Insert image by URL',
12
+ 'plugin.gallery.urlEditorLabel': 'Image URL',
13
+ 'plugin.gallery.urlEditorPlaceholder': 'https://example.com/image.jpg',
14
+ 'plugin.gallery.sourceSubmit': 'Insert',
15
+ 'plugin.gallery.sourceCancel': 'Cancel',
16
+ 'plugin.gallery.invalidUrl': 'Enter a valid image URL.',
9
17
  'plugin.gallery.addMore': 'Add more',
10
18
  'plugin.gallery.delete': 'Delete',
11
19
  'plugin.gallery.deleteAll': 'Delete all',
@@ -30,6 +38,6 @@ export default {
30
38
  'plugin.gallery.layoutAuto': 'Automatic layout',
31
39
  'plugin.gallery.layoutMasonry': 'Masonry layout',
32
40
  'plugin.gallery.layoutTriptych': 'Triptych layout',
33
- 'plugin.gallery.layoutTemplate': 'Layout template',
34
- 'plugin.gallery.emptyReadonly': 'No images',
35
- }
41
+ 'plugin.gallery.layoutTemplate': 'Layout template',
42
+ 'plugin.gallery.emptyReadonly': 'No images',
43
+ }
@@ -6,6 +6,14 @@ declare const _default: {
6
6
  'plugin.gallery.dropzone': string;
7
7
  'plugin.gallery.dropzoneUpload': string;
8
8
  'plugin.gallery.dropzoneText': string;
9
+ 'plugin.gallery.dropzoneUrlPrefix': string;
10
+ 'plugin.gallery.dropzoneUrl': string;
11
+ 'plugin.gallery.urlEditorTitle': string;
12
+ 'plugin.gallery.urlEditorLabel': string;
13
+ 'plugin.gallery.urlEditorPlaceholder': string;
14
+ 'plugin.gallery.sourceSubmit': string;
15
+ 'plugin.gallery.sourceCancel': string;
16
+ 'plugin.gallery.invalidUrl': string;
9
17
  'plugin.gallery.addMore': string;
10
18
  'plugin.gallery.delete': string;
11
19
  'plugin.gallery.deleteAll': string;
@@ -6,6 +6,14 @@ export default {
6
6
  'plugin.gallery.dropzone': 'или перетащите файлы сюда',
7
7
  'plugin.gallery.dropzoneUpload': 'Загрузите',
8
8
  'plugin.gallery.dropzoneText': 'изображения с устройства или перетащите их сюда',
9
+ 'plugin.gallery.dropzoneUrlPrefix': 'или',
10
+ 'plugin.gallery.dropzoneUrl': 'вставьте по URL',
11
+ 'plugin.gallery.urlEditorTitle': 'Вставка изображения по URL',
12
+ 'plugin.gallery.urlEditorLabel': 'URL изображения',
13
+ 'plugin.gallery.urlEditorPlaceholder': 'https://example.com/image.jpg',
14
+ 'plugin.gallery.sourceSubmit': 'Вставить',
15
+ 'plugin.gallery.sourceCancel': 'Отмена',
16
+ 'plugin.gallery.invalidUrl': 'Введите корректный URL изображения.',
9
17
  'plugin.gallery.addMore': 'Добавить ещё',
10
18
  'plugin.gallery.delete': 'Удалить',
11
19
  'plugin.gallery.deleteAll': 'Удалить всё',
@@ -30,6 +38,6 @@ export default {
30
38
  'plugin.gallery.layoutAuto': 'Автоматический макет',
31
39
  'plugin.gallery.layoutMasonry': 'Кладочный макет',
32
40
  'plugin.gallery.layoutTriptych': 'Триптих',
33
- 'plugin.gallery.layoutTemplate': 'Шаблон макета',
34
- 'plugin.gallery.emptyReadonly': 'Нет изображений',
35
- }
41
+ 'plugin.gallery.layoutTemplate': 'Шаблон макета',
42
+ 'plugin.gallery.emptyReadonly': 'Нет изображений',
43
+ }
@@ -3,6 +3,7 @@
3
3
  * @property {(key: string, fallback: string) => string} t
4
4
  * @property {boolean} readOnly
5
5
  * @property {() => void} onUploadClick
6
+ * @property {() => void} onOpenUrlEditor
6
7
  * @property {Array<{ icon?: string, label: string, handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null> }>} customActions
7
8
  * @property {(handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null>) => Promise<void>} runCustomAction
8
9
  * @property {(files: File[]) => void} onFilesDropped
@@ -21,6 +22,7 @@ export type EmptyViewDeps = {
21
22
  t: (key: string, fallback: string) => string;
22
23
  readOnly: boolean;
23
24
  onUploadClick: () => void;
25
+ onOpenUrlEditor: () => void;
24
26
  customActions: Array<{
25
27
  icon?: string;
26
28
  label: string;
@@ -1,13 +1,14 @@
1
- import { renderDropzone } from '../shared/dropzone.js'
2
- import { isSupportedImageFile } from '../shared/fileInput.js'
1
+ import { renderDropzone } from '../shared/dropzone.js'
2
+ import { isSupportedImageFile } from '../shared/fileInput.js'
3
3
  import { CSS } from './css.js'
4
4
  import { ICON_SELECT } from './icons.js'
5
5
 
6
6
  /**
7
- * @typedef {Object} EmptyViewDeps
8
- * @property {(key: string, fallback: string) => string} t
9
- * @property {boolean} readOnly
7
+ * @typedef {Object} EmptyViewDeps
8
+ * @property {(key: string, fallback: string) => string} t
9
+ * @property {boolean} readOnly
10
10
  * @property {() => void} onUploadClick
11
+ * @property {() => void} onOpenUrlEditor
11
12
  * @property {Array<{ icon?: string, label: string, handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null> }>} customActions
12
13
  * @property {(handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null>) => Promise<void>} runCustomAction
13
14
  * @property {(files: File[]) => void} onFilesDropped
@@ -17,11 +18,11 @@ import { ICON_SELECT } from './icons.js'
17
18
  * Render the empty-state dropzone for the Gallery plugin.
18
19
  * Replaces wrapper contents and removes the `filled` class.
19
20
  *
20
- * @param {HTMLElement} wrapper
21
- * @param {import('./state.js').GalleryState} state
22
- * @param {EmptyViewDeps} deps
23
- * @returns {void}
24
- */
21
+ * @param {HTMLElement} wrapper
22
+ * @param {import('./state.js').GalleryState} state
23
+ * @param {EmptyViewDeps} deps
24
+ * @returns {void}
25
+ */
25
26
  export function renderEmptyView(wrapper, state, deps) {
26
27
  state.resetTransient()
27
28
 
@@ -38,18 +39,23 @@ export function renderEmptyView(wrapper, state, deps) {
38
39
  filled: CSS.filled,
39
40
  }, {
40
41
  iconHtml: ICON_SELECT,
41
- uploadText: deps.t('dropzoneUpload', 'Upload'),
42
- afterText: deps.t('dropzoneText', 'images from your device or drag and drop them here'),
43
- readOnly: deps.readOnly,
44
- emptyText: deps.t('emptyReadonly', 'No images'),
42
+ uploadText: deps.t('dropzoneUpload', 'Upload'),
43
+ afterText: deps.t('dropzoneText', 'images from your device or drag and drop them here'),
44
+ readOnly: deps.readOnly,
45
+ emptyText: deps.t('emptyReadonly', 'No images'),
45
46
  onUploadClick: deps.onUploadClick,
47
+ inlineActions: [{
48
+ prefix: deps.t('dropzoneUrlPrefix', 'or'),
49
+ label: deps.t('dropzoneUrl', 'insert by URL'),
50
+ onSelect: deps.onOpenUrlEditor,
51
+ }],
46
52
  actions: deps.customActions.map(action => ({
47
53
  icon: action.icon,
48
54
  label: action.label,
49
55
  onSelect: () => { void deps.runCustomAction(action.handler) },
50
56
  })),
51
57
  onDrop: (dt) => {
52
- const files = [...(dt.files || [])].filter(isSupportedImageFile)
58
+ const files = [...(dt.files || [])].filter(isSupportedImageFile)
53
59
  if (files.length > 0) deps.onFilesDropped(files)
54
60
  },
55
61
  })
@@ -9,7 +9,7 @@
9
9
  * @property {(operation: () => void) => void} mutate
10
10
  * @property {(files: File[]) => void} onFilesDropped
11
11
  * @property {() => void} onTriggerFileInput
12
- * @property {() => void} onPromptUrl
12
+ * @property {() => void} onOpenUrlEditor
13
13
  * @property {() => void} onDeleteAll
14
14
  * @property {Array<{ icon?: string, label: string, handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null> }>} customActions
15
15
  * @property {(handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null>) => Promise<void>} runCustomAction
@@ -34,7 +34,7 @@ export type FilledViewDeps = {
34
34
  mutate: (operation: () => void) => void;
35
35
  onFilesDropped: (files: File[]) => void;
36
36
  onTriggerFileInput: () => void;
37
- onPromptUrl: () => void;
37
+ onOpenUrlEditor: () => void;
38
38
  onDeleteAll: () => void;
39
39
  customActions: Array<{
40
40
  icon?: string;
@@ -13,11 +13,12 @@ import { buildSettingsPanel } from './settings.js'
13
13
  import {
14
14
  attachExternalDrop, createEmptySlot, createFilledSlot, createOverflowItem,
15
15
  } from './slot.js'
16
+ import { createPluginLayer } from '../shared/layer.js'
16
17
 
17
18
  /**
18
- * @typedef {Object} FilledViewDeps
19
- * @property {(key: string, fallback: string) => string} t
20
- * @property {boolean} readOnly
19
+ * @typedef {Object} FilledViewDeps
20
+ * @property {(key: string, fallback: string) => string} t
21
+ * @property {boolean} readOnly
21
22
  * @property {() => void} syncCaptions
22
23
  * @property {() => import('./state.js').GalleryState | undefined} getState
23
24
  * @property {() => void} reRender
@@ -25,7 +26,7 @@ import {
25
26
  * @property {(operation: () => void) => void} mutate
26
27
  * @property {(files: File[]) => void} onFilesDropped
27
28
  * @property {() => void} onTriggerFileInput
28
- * @property {() => void} onPromptUrl
29
+ * @property {() => void} onOpenUrlEditor
29
30
  * @property {() => void} onDeleteAll
30
31
  * @property {Array<{ icon?: string, label: string, handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null> }>} customActions
31
32
  * @property {(handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null>) => Promise<void>} runCustomAction
@@ -35,11 +36,11 @@ import {
35
36
  * Render the filled-state Gallery view: template grid (or masonry) +
36
37
  * optional overflow row + action bar.
37
38
  *
38
- * @param {HTMLElement} wrapper
39
- * @param {import('./state.js').GalleryState} state
40
- * @param {FilledViewDeps} deps
41
- * @returns {void}
42
- */
39
+ * @param {HTMLElement} wrapper
40
+ * @param {import('./state.js').GalleryState} state
41
+ * @param {FilledViewDeps} deps
42
+ * @returns {void}
43
+ */
43
44
  export function renderFilledView(wrapper, state, deps) {
44
45
  state.resetTransient()
45
46
  wrapper.innerHTML = ''
@@ -54,7 +55,7 @@ export function renderFilledView(wrapper, state, deps) {
54
55
  }
55
56
 
56
57
  applyGalleryStyles(wrapper, state)
57
- if (!deps.readOnly) wrapper.appendChild(renderActions(wrapper, state, deps, signal))
58
+ if (!deps.readOnly) wrapper.appendChild(renderActions(wrapper, state, deps, signal))
58
59
  }
59
60
 
60
61
  /**
@@ -77,7 +78,7 @@ function renderMasonry(wrapper, state, deps, signal) {
77
78
  grid.appendChild(slot)
78
79
  })
79
80
 
80
- if (!deps.readOnly) attachExternalDrop(grid, signal, deps.onFilesDropped)
81
+ if (!deps.readOnly) attachExternalDrop(grid, signal, deps.onFilesDropped)
81
82
  wrapper.appendChild(grid)
82
83
  }
83
84
 
@@ -125,20 +126,20 @@ function renderSlotBased(wrapper, state, deps, signal) {
125
126
  const slot = createFilledSlot(img, idx, signal, slotDeps)
126
127
  slot.dataset.slot = String(idx)
127
128
 
128
- const imgEl = /** @type {HTMLImageElement | null} */ (slot.querySelector(`.${CSS.slotImg}`))
129
- if (imgEl) {
130
- let ready = false
131
- const onReady = () => {
132
- if (ready) return
133
- ready = true
134
- orientations[idx] = classifyOrientation(imgEl.naturalWidth, imgEl.naturalHeight)
135
- loadedCount++
136
- if (loadedCount >= slotCount) onAllLoaded()
137
- }
138
- imgEl.addEventListener('load', onReady, { once: true, signal })
139
- imgEl.addEventListener('error', onReady, { once: true, signal })
140
- if (imgEl.complete) queueMicrotask(onReady)
141
- }
129
+ const imgEl = /** @type {HTMLImageElement | null} */ (slot.querySelector(`.${CSS.slotImg}`))
130
+ if (imgEl) {
131
+ let ready = false
132
+ const onReady = () => {
133
+ if (ready) return
134
+ ready = true
135
+ orientations[idx] = classifyOrientation(imgEl.naturalWidth, imgEl.naturalHeight)
136
+ loadedCount++
137
+ if (loadedCount >= slotCount) onAllLoaded()
138
+ }
139
+ imgEl.addEventListener('load', onReady, { once: true, signal })
140
+ imgEl.addEventListener('error', onReady, { once: true, signal })
141
+ if (imgEl.complete) queueMicrotask(onReady)
142
+ }
142
143
  grid.appendChild(slot)
143
144
  }
144
145
  } else {
@@ -155,7 +156,7 @@ function renderSlotBased(wrapper, state, deps, signal) {
155
156
  }
156
157
  }
157
158
 
158
- if (!deps.readOnly) attachExternalDrop(grid, signal, deps.onFilesDropped)
159
+ if (!deps.readOnly) attachExternalDrop(grid, signal, deps.onFilesDropped)
159
160
  wrapper.appendChild(grid)
160
161
 
161
162
  if (overflowImages.length > 0) {
@@ -167,7 +168,7 @@ function renderSlotBased(wrapper, state, deps, signal) {
167
168
  overflow.appendChild(createOverflowItem(img, globalIdx, signal, slotDeps))
168
169
  })
169
170
 
170
- if (!deps.readOnly) attachExternalDrop(overflow, signal, deps.onFilesDropped)
171
+ if (!deps.readOnly) attachExternalDrop(overflow, signal, deps.onFilesDropped)
171
172
  wrapper.appendChild(overflow)
172
173
  }
173
174
  }
@@ -180,9 +181,9 @@ function renderSlotBased(wrapper, state, deps, signal) {
180
181
  * @returns {import('./slot.js').SlotDeps}
181
182
  */
182
183
  function makeSlotDeps(deps) {
183
- return {
184
- t: deps.t,
185
- readOnly: deps.readOnly,
184
+ return {
185
+ t: deps.t,
186
+ readOnly: deps.readOnly,
186
187
  syncCaptions: deps.syncCaptions,
187
188
  getState: deps.getState,
188
189
  onRemoveImage: (index) => {
@@ -229,37 +230,41 @@ function renderActions(wrapper, state, deps, signal) {
229
230
  dropdown.className = CSS.dropdown
230
231
 
231
232
  const settingsBtn = document.createElement('button')
232
- settingsBtn.type = 'button'
233
- settingsBtn.className = CSS.actionBtn
234
- settingsBtn.innerHTML = `${ICON_SETTINGS} ${deps.t('settings', 'Settings')}`
235
- settingsBtn.setAttribute('aria-haspopup', 'true')
236
- settingsBtn.setAttribute('aria-expanded', 'false')
237
-
238
- const panel = buildSettingsPanel(wrapper, state, settingsDeps)
239
- panel.setAttribute('role', 'group')
240
- panel.setAttribute('aria-label', deps.t('settings', 'Settings'))
233
+ settingsBtn.type = 'button'
234
+ settingsBtn.className = CSS.actionBtn
235
+ settingsBtn.innerHTML = `${ICON_SETTINGS} ${deps.t('settings', 'Settings')}`
236
+ settingsBtn.setAttribute('aria-haspopup', 'true')
237
+ settingsBtn.setAttribute('aria-expanded', 'false')
238
+
239
+ const panel = buildSettingsPanel(wrapper, state, settingsDeps)
240
+ panel.setAttribute('role', 'group')
241
+ panel.setAttribute('aria-label', deps.t('settings', 'Settings'))
242
+ const settingsLayer = createPluginLayer(wrapper, signal)
243
+ const setSettingsOpen = (open) => {
244
+ dropdown.classList.toggle(CSS.dropdownOpen, open)
245
+ settingsBtn.setAttribute('aria-expanded', String(open))
246
+ if (open) settingsLayer.open()
247
+ else settingsLayer.close()
248
+ }
241
249
 
242
250
  settingsBtn.addEventListener('click', (e) => {
243
251
  e.stopPropagation()
244
- const open = dropdown.classList.toggle(CSS.dropdownOpen)
245
- settingsBtn.setAttribute('aria-expanded', String(open))
252
+ setSettingsOpen(!dropdown.classList.contains(CSS.dropdownOpen))
246
253
  }, { signal })
247
254
 
248
255
  dropdown.append(settingsBtn, panel)
249
256
 
250
257
  document.addEventListener('click', (e) => {
251
258
  if (!dropdown.contains(/** @type {Node} */ (e.target))) {
252
- dropdown.classList.remove(CSS.dropdownOpen)
253
- settingsBtn.setAttribute('aria-expanded', 'false')
254
- }
255
- }, { signal })
256
- dropdown.addEventListener('keydown', (event) => {
257
- if (event.key !== 'Escape' || !dropdown.classList.contains(CSS.dropdownOpen)) return
258
- event.preventDefault()
259
- dropdown.classList.remove(CSS.dropdownOpen)
260
- settingsBtn.setAttribute('aria-expanded', 'false')
261
- settingsBtn.focus()
262
- }, { signal })
259
+ setSettingsOpen(false)
260
+ }
261
+ }, { signal })
262
+ dropdown.addEventListener('keydown', (event) => {
263
+ if (event.key !== 'Escape' || !dropdown.classList.contains(CSS.dropdownOpen)) return
264
+ event.preventDefault()
265
+ setSettingsOpen(false)
266
+ settingsBtn.focus()
267
+ }, { signal })
263
268
 
264
269
  // Main view container (for drill-down hide/show)
265
270
  const mainView = document.createElement('div')
@@ -283,9 +288,9 @@ function renderActions(wrapper, state, deps, signal) {
283
288
  // Delete all
284
289
  const deleteAllBtn = document.createElement('button')
285
290
  deleteAllBtn.type = 'button'
286
- deleteAllBtn.className = `${CSS.actionBtn} ${CSS.actionBtnDanger}`
287
- deleteAllBtn.innerHTML = ICON_TRASH
288
- deleteAllBtn.setAttribute('aria-label', deps.t('deleteAll', 'Delete all'))
291
+ deleteAllBtn.className = `${CSS.actionBtn} ${CSS.actionBtnDanger}`
292
+ deleteAllBtn.innerHTML = ICON_TRASH
293
+ deleteAllBtn.setAttribute('aria-label', deps.t('deleteAll', 'Delete all'))
289
294
  deleteAllBtn.addEventListener('mousedown', (e) => e.preventDefault(), { signal })
290
295
  deleteAllBtn.addEventListener('click', (e) => {
291
296
  e.stopPropagation()
@@ -335,7 +340,7 @@ function showAddView(actions, mainView, deps, signal) {
335
340
 
336
341
  view.appendChild(makeActionBtn(
337
342
  `${ICON_URL} URL`,
338
- () => { deps.onPromptUrl(); restore() },
343
+ () => { deps.onOpenUrlEditor(); restore() },
339
344
  signal,
340
345
  ))
341
346
 
@@ -1,4 +1,5 @@
1
1
  .oe-image {
2
+ position: relative;
2
3
  border-radius: 0.5rem;
3
4
  overflow-anchor: none;
4
5
  text-align: center;
@@ -239,7 +240,7 @@
239
240
  border-radius: 8px;
240
241
  box-shadow: var(--oe-toolbar-shadow, 0 8px 24px rgba(0, 0, 0, 0.4));
241
242
  padding: 12px;
242
- z-index: 100;
243
+ z-index: var(--oe-plugin-panel-z-index, 1100);
243
244
  }
244
245
 
245
246
  .oe-image__dropdown--open .oe-image__dropdown-panel {
@@ -377,7 +378,7 @@
377
378
  border: 1px solid var(--oe-border-hover, #2a2a2a);
378
379
  border-radius: 6px;
379
380
  box-shadow: var(--oe-toolbar-shadow, 0 8px 24px rgba(0, 0, 0, 0.4));
380
- z-index: 110;
381
+ z-index: var(--oe-plugin-popover-z-index, 1120);
381
382
  padding: 3px;
382
383
  max-height: 10rem;
383
384
  overflow-y: auto;
@@ -516,6 +517,10 @@
516
517
  color: var(--oe-text-1, #1a1a1a);
517
518
  }
518
519
 
520
+ .oe-theme-light .oe-image__action-btn:hover {
521
+ color: var(--oe-text-on-accent, #fff);
522
+ }
523
+
519
524
  .oe-theme-light .oe-image__dropdown-panel {
520
525
  background: var(--oe-card, #fff);
521
526
  border-color: var(--oe-border-hover, #d4d4d4);