Browse Source

Feature: Mobile - Improve Editor support

Vladimir Sheremet 2 years ago
parent
commit
a4ba2bdec5

+ 21 - 2
.cypress/utils/index.ts

@@ -18,6 +18,12 @@ import type { mount } from 'cypress/vue'
 import { createMemoryHistory, createRouter } from 'vue-router'
 import type { App } from 'vue'
 
+import { cacheInitializerModules } from '@mobile/server/apollo'
+import createCache from '@shared/server/apollo/cache'
+
+import { createMockClient } from 'mock-apollo-client'
+import { provideApolloClient } from '@vue/apollo-composable'
+
 const router = createRouter({
   history: createMemoryHistory('/'),
   routes: [{ path: '/', component: { template: '<div />' } }],
@@ -37,6 +43,15 @@ export const mountComponent: typeof mount = (
   return cy.mount(component, merge({ global: { plugins } }, options))
 }
 
+export const mockApolloClient = () => {
+  const client = createMockClient({
+    cache: createCache(cacheInitializerModules),
+    queryDeduplication: true,
+  })
+  provideApolloClient(client)
+  return client
+}
+
 export const mountFormField = (
   field: string,
   props?: Partial<FormSchemaField> & Record<string, unknown>,
@@ -57,13 +72,17 @@ interface CheckFormMatchOptions {
 }
 
 export const checkFormMatchesSnapshot = (options?: CheckFormMatchOptions) => {
-  const title = options?.subTitle ? `${Cypress.currentTest.title} - ${options.subTitle}` : Cypress.currentTest.title
+  const title = options?.subTitle
+    ? `${Cypress.currentTest.title} - ${options.subTitle}`
+    : Cypress.currentTest.title
   const wrapperSelector = options?.wrapperSelector || '.formkit-outer'
 
   return cy.wrap(document.fonts.ready).then(() => {
     cy.get(wrapperSelector).matchImage({
       title,
-      imagesDir: options?.type ? `__image_snapshots__/${options.type}` : undefined,
+      imagesDir: options?.type
+        ? `__image_snapshots__/${options.type}`
+        : undefined,
     })
   })
 }

+ 2 - 0
app/frontend/apps/mobile/form/theme/global/addFloatingTextareaLabel.ts

@@ -30,6 +30,7 @@ export const addFloatingTextareaLabel = (classes: Classes = {}) => {
       border-none
       focus:outline-none
       placeholder:text-transparent
+      min-h-[100px]
     `),
     label: clean(`
       ${label}
@@ -40,6 +41,7 @@ export const addFloatingTextareaLabel = (classes: Classes = {}) => {
       h-2
       translate-y-4
       text-base
+      cursor-text
       transition-all duration-100 ease-in-out origin-left
       formkit-populated:translate-y-0
       formkit-populated:text-xs formkit-populated:opacity-75

+ 2 - 5
app/frontend/apps/mobile/form/theme/global/getCoreClasses.ts

@@ -54,11 +54,8 @@ const getCoreClasses: FormThemeExtension = (classes: FormThemeClasses) => {
     password: addAbsoluteFloatingLabel(classes.password),
     date: addDateLabel(classes.date),
     datetime: addDateLabel(classes.datetime),
-    textarea: addFloatingTextareaLabel({
-      ...classes.textarea,
-      label: `${classes.textarea?.label} cursor-text`,
-      input: `${classes.textarea?.input} min-h-[100px]`,
-    }),
+    editor: addFloatingTextareaLabel(classes.editor),
+    textarea: addFloatingTextareaLabel(classes.textarea),
     checkbox: {
       outer: 'formkit-invalid:bg-red-dark',
       wrapper: `${

+ 7 - 0
app/frontend/apps/mobile/pages/playground/views/PlaygroundOverview.vue

@@ -12,9 +12,16 @@ import CommonStepper from '@mobile/components/CommonStepper/CommonStepper.vue'
 import { ref } from 'vue'
 
 const linkSchemaRaw = [
+  {
+    type: 'editor',
+    name: 'editor',
+    label: 'Editor',
+    required: true,
+  },
   {
     type: 'textarea',
     name: 'textarea',
+    id: 'textarea',
     label: 'Textarea',
   },
   {

+ 7 - 0
app/frontend/apps/mobile/pages/ticket/views/TicketCreate.vue

@@ -33,6 +33,13 @@ const additionalFormSchema = [
         name: 'body',
         label: 'TESTING',
         screen: 'create_top',
+        props: {
+          meta: {
+            mentionUser: {
+              groupNodeId: 'form_field_group_id',
+            },
+          },
+        },
         object: EnumObjectManagerObjects.TicketArticle,
       },
     ],

+ 2 - 4
app/frontend/apps/mobile/server/apollo/index.ts

@@ -7,10 +7,8 @@ import type {
   CacheInitializerModules,
 } from '@shared/types/server/apollo/client'
 
-const cacheInitializerModules: CacheInitializerModules = import.meta.glob(
-  './cache/initializer/*.ts',
-  { eager: true },
-)
+export const cacheInitializerModules: CacheInitializerModules =
+  import.meta.glob('./cache/initializer/*.ts', { eager: true })
 
 const initializeApolloClient: InitializeAppApolloClient = (app: App) => {
   mainInitializeApolloClient(app, cacheInitializerModules)

+ 12 - 5
app/frontend/apps/mobile/styles/main.scss

@@ -6,11 +6,6 @@
     outline: none;
   }
 
-  &::before {
-    content: attr(aria-placeholder);
-    @apply absolute cursor-text text-white/50;
-  }
-
   ol {
     list-style: decimal;
   }
@@ -30,6 +25,18 @@
     }
   }
 
+  h1 {
+    @apply mb-2 mt-1 text-2xl font-bold;
+  }
+
+  h2 {
+    @apply my-1 text-xl font-bold;
+  }
+
+  h3 {
+    @apply my-1 text-lg font-bold;
+  }
+
   a {
     @apply text-blue;
   }

+ 18 - 16
app/frontend/cypress/shared/components/Form/fields/FieldEditor/editor-actions.cy.ts

@@ -25,10 +25,10 @@ const testAction = (action: string, expected: (text: string) => string) => {
 }
 
 describe('testing actions', () => {
-  testAction('underline', (text) => `<u>${text}</u>`)
-  testAction('bold', (text) => `<strong>${text}</strong>`)
-  testAction('italic', (text) => `<em>${text}</em>`)
-  testAction('strike', (text) => `<s>${text}</s>`)
+  testAction('Format as underlined', (text) => `<u>${text}</u>`)
+  testAction('Format as bold', (text) => `<strong>${text}</strong>`)
+  testAction('Format as italic', (text) => `<em>${text}</em>`)
+  testAction('Format as strikethrough', (text) => `<s>${text}</s>`)
   testAction('Add first level heading', (text) => `<h1>${text}</h1>`)
   testAction('Add second level heading', (text) => `<h2>${text}</h2>`)
   testAction('Add third level heading', (text) => `<h3>${text}</h3>`)
@@ -39,7 +39,7 @@ describe('testing actions', () => {
     it('removes formatting', () => {
       mountEditor()
       cy.findByRole('textbox').click()
-      cy.findByTestId('action-bar').findByLabelText('bold').click()
+      cy.findByTestId('action-bar').findByLabelText('Format as bold').click()
       cy.findByRole('textbox')
         .type('Text')
         .should('have.html', '<p><strong>Text</strong></p>')
@@ -62,7 +62,7 @@ describe('testing actions', () => {
     })
   })
 
-  it.only('makes text into a link', () => {
+  it('makes text into a link', () => {
     cy.window().then((win) => {
       cy.stub(win, 'prompt').returns('https://example.com')
       mountEditor()
@@ -83,16 +83,18 @@ describe('testing actions', () => {
     cy.findByRole('textbox').click()
     cy.findByTestId('action-bar')
       .findByLabelText('Add image')
-      .find('input[type="file"]')
-      .selectFile(
-        {
-          contents: imageBuffer,
-          fileName: 'file.png',
-          mimeType: 'image/png',
-          lastModified: Date.now(),
-        },
-        { force: true },
-      )
+      .click() // click inserts input into DOM
+      .then(() => {
+        cy.findByTestId('editor-image-input').selectFile(
+          {
+            contents: imageBuffer,
+            fileName: 'file.png',
+            mimeType: 'image/png',
+            lastModified: Date.now(),
+          },
+          { force: true },
+        )
+      })
 
     cy.findByRole('textbox')
       .find('img')

+ 0 - 12
app/frontend/cypress/shared/components/Form/fields/FieldEditor/editor-basic.cy.ts

@@ -61,18 +61,6 @@ describe('FieldEditor basic functionality', { retries: 2 }, () => {
       .and('have.html', '<p><strong>Hello, World!</strong></p>')
   })
 
-  it('has placeholder, when needed', () => {
-    mountEditor({
-      placeholder: 'Placeholder...',
-    })
-
-    cy.findByRole('textbox')
-      .should('have.attr', 'aria-placeholder', 'Placeholder...')
-      .click()
-      .type('Hello, World!')
-      .should('not.have.attr', 'aria-placeholder')
-  })
-
   it('pasting images inlines them', () => {
     mountEditor()
 

+ 12 - 10
app/frontend/cypress/shared/components/Form/fields/FieldEditor/editor-image-resize.cy.ts

@@ -8,16 +8,18 @@ describe('resizing image within editor', () => {
     cy.findByRole('textbox').click()
     cy.findByTestId('action-bar')
       .findByLabelText('Add image')
-      .find('input[type="file"]')
-      .selectFile(
-        {
-          contents: '.cypress/fixtures/example.png',
-          fileName: 'example.png',
-          mimeType: 'image/png',
-          lastModified: Date.now(),
-        },
-        { force: true },
-      )
+      .click() // click inserts input into DOM
+      .then(() => {
+        cy.findByTestId('editor-image-input').selectFile(
+          {
+            contents: '.cypress/fixtures/example.png',
+            fileName: 'file.png',
+            mimeType: 'image/png',
+            lastModified: Date.now(),
+          },
+          { force: true },
+        )
+      })
     cy.findByRole('textbox').get('img:first').trigger('click')
 
     cy.get('.vdr-handle:last')

Some files were not shown because too many files changed in this diff