diff --git a/packages/web-app-files/src/composables/actions/spaces/useSpaceActionsSetIcon.ts b/packages/web-app-files/src/composables/actions/spaces/useSpaceActionsSetIcon.ts
index 9eae09f0433..69d79565c87 100644
--- a/packages/web-app-files/src/composables/actions/spaces/useSpaceActionsSetIcon.ts
+++ b/packages/web-app-files/src/composables/actions/spaces/useSpaceActionsSetIcon.ts
@@ -37,7 +37,7 @@ export const useSpaceActionsSetIcon = () => {
dispatchModal({
elementClass: 'w-auto',
title: $gettext('Set icon for ยป%{space}ยซ', { space: resources[0].name }),
- hideConfirmButton: true,
+ hideActions: true,
customComponent: markRaw(EmojiPickerModal),
focusTrapInitial: false,
onConfirm: (emoji: string) => setIconSpace(resources[0], emoji)
diff --git a/packages/web-pkg/src/components/Modals/EmojiPickerModal.vue b/packages/web-pkg/src/components/Modals/EmojiPickerModal.vue
index 083c8eb1677..a5a8cf8d9b0 100644
--- a/packages/web-pkg/src/components/Modals/EmojiPickerModal.vue
+++ b/packages/web-pkg/src/components/Modals/EmojiPickerModal.vue
@@ -1,5 +1,7 @@
-
+
+
+
+
diff --git a/packages/web-pkg/src/editor/composables/strategies/html.ts b/packages/web-pkg/src/editor/composables/strategies/html.ts
index 2f6a315b983..5a1b431e4a5 100644
--- a/packages/web-pkg/src/editor/composables/strategies/html.ts
+++ b/packages/web-pkg/src/editor/composables/strategies/html.ts
@@ -202,8 +202,8 @@ export const useStrategyHtml = (editorState: TextEditorState): ContentTypeStrate
imageUpload(),
imageCloud(),
createTable(),
- menuEmoji(),
- horizontalRule()
+ horizontalRule(),
+ menuEmoji()
]
},
{
diff --git a/packages/web-pkg/src/editor/composables/strategies/markdown.ts b/packages/web-pkg/src/editor/composables/strategies/markdown.ts
index 99237975647..1d024d0ae6c 100644
--- a/packages/web-pkg/src/editor/composables/strategies/markdown.ts
+++ b/packages/web-pkg/src/editor/composables/strategies/markdown.ts
@@ -246,8 +246,8 @@ export const useStrategyMarkdown = (editorState: TextEditorState): ContentTypeSt
addColumnAfter(),
deleteColumn(),
deleteTable(),
- menuEmoji(),
horizontalRule(),
+ menuEmoji(),
frontmatter()
]
},
diff --git a/packages/web-pkg/src/editor/composables/strategies/tiptapJson.ts b/packages/web-pkg/src/editor/composables/strategies/tiptapJson.ts
index 710c8873ecd..af82a320ebf 100644
--- a/packages/web-pkg/src/editor/composables/strategies/tiptapJson.ts
+++ b/packages/web-pkg/src/editor/composables/strategies/tiptapJson.ts
@@ -192,8 +192,8 @@ export const useStrategyTiptapJson = (editorState: TextEditorState): ContentType
imageUpload(),
imageCloud(),
createTable(),
- menuEmoji(),
- horizontalRule()
+ horizontalRule(),
+ menuEmoji()
]
},
{
diff --git a/packages/web-pkg/src/editor/composables/useEditorActions.ts b/packages/web-pkg/src/editor/composables/useEditorActions.ts
index 89aebdc499e..1a18b600638 100644
--- a/packages/web-pkg/src/editor/composables/useEditorActions.ts
+++ b/packages/web-pkg/src/editor/composables/useEditorActions.ts
@@ -8,6 +8,7 @@ import { OcEmojiPicker } from '@opencloud-eu/design-system/components'
import { useModals, useThemeStore } from '../../composables'
import { useClientService, useGetMatchingSpace, useFolderLink } from '../../composables'
import FilePickerModal from '../../components/Modals/FilePickerModal.vue'
+import EmojiPickerModal from '../../components/Modals/EmojiPickerModal.vue'
import { arrayBufferToDataUrl, withoutExtension } from '../../helpers'
import { TextEditorState } from '../types'
import { requestLinkPanel, printEditorContent } from '../helpers'
@@ -741,7 +742,18 @@ export function useEditorActions(state: TextEditorState) {
icon: 'emoji-sticker',
iconFillType: 'line',
keywords: ['emoji', 'smiley', 'emoticon'],
- showInSlashCommands: false,
+ showInSlashCommands: true,
+ slashCommandAction: ({ editor, range }) => {
+ editor.chain().focus().deleteRange(range).run()
+ dispatchModal({
+ title: $gettext('Insert emoji'),
+ customComponent: markRaw(EmojiPickerModal),
+ hideActions: true,
+ onConfirm: (emoji: string) => {
+ editor.chain().focus().insertContent(emoji).run()
+ }
+ })
+ },
menuCloseOnClick: false,
menuComponent: markRaw(OcEmojiPicker),
menuComponentAttrs: (editor, closeMenu) => ({
diff --git a/packages/web-pkg/tests/unit/editor/composables/useEditorActions.spec.ts b/packages/web-pkg/tests/unit/editor/composables/useEditorActions.spec.ts
index 373603f4e6e..14fe3d14028 100644
--- a/packages/web-pkg/tests/unit/editor/composables/useEditorActions.spec.ts
+++ b/packages/web-pkg/tests/unit/editor/composables/useEditorActions.spec.ts
@@ -1058,11 +1058,12 @@ describe('useEditorActions', () => {
})
describe('menuEmoji', () => {
- it('uses menu component mode and is hidden from slash commands', () => {
+ it('uses menu component mode and is available in slash commands', () => {
const action = actions.menuEmoji()
expect(action.id).toBe('menu-emoji')
expect(action.menuComponent).toBeTruthy()
- expect(action.showInSlashCommands).toBe(false)
+ expect(action.showInSlashCommands).toBe(true)
+ expect(action.slashCommandAction).toBeTypeOf('function')
})
it('menuComponentAttrs inserts selected emoji into editor', () => {
@@ -1077,6 +1078,24 @@ describe('useEditorActions', () => {
expect(editor._chain.run).toHaveBeenCalled()
expect(closeMenu).toHaveBeenCalled()
})
+
+ it('slashCommandAction removes slash token and opens emoji modal', () => {
+ const editor = createMockEditor()
+ const action = actions.menuEmoji()
+
+ action.slashCommandAction!({ editor, range: mockRange })
+
+ expect(editor._chain.deleteRange).toHaveBeenCalledWith(mockRange)
+
+ const store = useModals()
+ const modal = store.modals[0]
+ expect(modal.title).toBe('Insert emoji')
+ expect(modal.hideActions).toBe(true)
+
+ modal.onConfirm?.('๐')
+ expect(editor._chain.insertContent).toHaveBeenCalledWith('๐')
+ expect(editor._chain.run).toHaveBeenCalled()
+ })
})
describe('action metadata', () => {
diff --git a/packages/web-pkg/tests/unit/editor/composables/useTextEditor.spec.ts b/packages/web-pkg/tests/unit/editor/composables/useTextEditor.spec.ts
index f3b89163bec..dde67189a77 100644
--- a/packages/web-pkg/tests/unit/editor/composables/useTextEditor.spec.ts
+++ b/packages/web-pkg/tests/unit/editor/composables/useTextEditor.spec.ts
@@ -92,14 +92,14 @@ describe('useTextEditor', () => {
expect(pluginNames).toContain('slashCommands')
})
- it('does not register the extension for plain-text when all actions are hidden in slash commands', () => {
+ it('registers the extension for plain-text when a slash action is available', () => {
const { result } = createEditor({
contentType: 'plain-text',
modelValue: toRef('hi'),
slashCommands: true
})
const pluginNames = result.editor.value?.extensionManager.extensions.map((e) => e.name) ?? []
- expect(pluginNames).not.toContain('slashCommands')
+ expect(pluginNames).toContain('slashCommands')
})
})
diff --git a/packages/web-pkg/tests/unit/editor/strategies/html.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/html.spec.ts
index 1e12c97159b..b0576f58b8e 100644
--- a/packages/web-pkg/tests/unit/editor/strategies/html.spec.ts
+++ b/packages/web-pkg/tests/unit/editor/strategies/html.spec.ts
@@ -86,9 +86,10 @@ describe('useStrategyHtml', () => {
const tableToolsGroup = strategy
.editorActionGroups()
.find((group) => group.id === 'table-tools')
+ const insertIds = insertGroup?.actions.map((action) => action.id) ?? []
- expect(insertGroup?.actions.map((action) => action.id)).toContain('table')
- expect(insertGroup?.actions.map((action) => action.id)).not.toContain('add-row-before')
+ expect(insertIds).toContain('table')
+ expect(insertIds).not.toContain('add-row-before')
expect(tableToolsGroup?.actions.map((action) => action.id)).toEqual([
'toggle-header-row',
'add-row-before',
diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdown.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdown.spec.ts
index 05c25dadf72..a4dbb79cca7 100644
--- a/packages/web-pkg/tests/unit/editor/strategies/markdown.spec.ts
+++ b/packages/web-pkg/tests/unit/editor/strategies/markdown.spec.ts
@@ -144,14 +144,14 @@ describe('useStrategyMarkdown', () => {
expect(enabled.filter((id) => !allowed.includes(id) && !id.startsWith('zoom-'))).toEqual([])
})
- it('offers no slash entries in the frontmatter block', () => {
+ it('offers the emoji slash entry in the frontmatter block', () => {
const editor = editorIn('frontmatter')
const slashItems = allActions()
.filter((action) => action.showInSlashCommands !== false)
.filter((action) => action.isEnabled?.(editor) ?? true)
.map(({ id }) => id)
- expect(slashItems).toEqual([])
+ expect(slashItems).toEqual(['menu-emoji'])
})
it('leaves everything enabled outside the block', () => {
diff --git a/packages/web-pkg/tests/unit/editor/strategies/tiptapJson.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/tiptapJson.spec.ts
index a6b8c8401cb..3c13d019917 100644
--- a/packages/web-pkg/tests/unit/editor/strategies/tiptapJson.spec.ts
+++ b/packages/web-pkg/tests/unit/editor/strategies/tiptapJson.spec.ts
@@ -57,10 +57,11 @@ describe('useStrategyTiptapJson', () => {
const tableToolsGroup = strategy
.editorActionGroups()
.find((group) => group.id === 'table-tools')
+ const insertIds = insertGroup?.actions.map((action) => action.id) ?? []
- expect(insertGroup?.actions.map((action) => action.id)).toContain('image-cloud')
- expect(insertGroup?.actions.map((action) => action.id)).toContain('table')
- expect(insertGroup?.actions.map((action) => action.id)).not.toContain('add-row-before')
+ expect(insertIds).toContain('image-cloud')
+ expect(insertIds).toContain('table')
+ expect(insertIds).not.toContain('add-row-before')
expect(tableToolsGroup?.actions.map((action) => action.id)).toEqual([
'toggle-header-row',
'add-row-before',