From 57836cc17a57c790d2ffb2463abb16a03321eb59 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Tue, 17 Sep 2024 14:00:22 +0200 Subject: [PATCH] feat(editor): Add truncate directive (#10842) --- .../design-system/src/directives/index.ts | 1 + .../src/directives/n8n-truncate.test.ts | 76 +++++++++++++++++++ .../src/directives/n8n-truncate.ts | 26 +++++++ packages/design-system/src/main.ts | 1 + packages/design-system/src/plugin.ts | 5 ++ .../design-system/src/utils/string.test.ts | 17 +++++ packages/design-system/src/utils/string.ts | 2 + 7 files changed, 128 insertions(+) create mode 100644 packages/design-system/src/directives/index.ts create mode 100644 packages/design-system/src/directives/n8n-truncate.test.ts create mode 100644 packages/design-system/src/directives/n8n-truncate.ts create mode 100644 packages/design-system/src/utils/string.test.ts create mode 100644 packages/design-system/src/utils/string.ts diff --git a/packages/design-system/src/directives/index.ts b/packages/design-system/src/directives/index.ts new file mode 100644 index 0000000000..eb939f0531 --- /dev/null +++ b/packages/design-system/src/directives/index.ts @@ -0,0 +1 @@ +export { n8nTruncate } from './n8n-truncate'; diff --git a/packages/design-system/src/directives/n8n-truncate.test.ts b/packages/design-system/src/directives/n8n-truncate.test.ts new file mode 100644 index 0000000000..ec8922d2bc --- /dev/null +++ b/packages/design-system/src/directives/n8n-truncate.test.ts @@ -0,0 +1,76 @@ +import { render } from '@testing-library/vue'; +import { n8nTruncate } from './n8n-truncate'; + +describe('Directive n8n-truncate', () => { + it('should truncate text to 30 chars by default', async () => { + const { html } = render( + { + props: { + text: { + type: String, + }, + }, + template: '
{{text}}
', + }, + { + props: { + text: 'This is a very long text that should be truncated', + }, + global: { + directives: { + n8nTruncate, + }, + }, + }, + ); + expect(html()).toBe('
This is a very long text that...
'); + }); + + it('should truncate text to 30 chars in case of wrong argument', async () => { + const { html } = render( + { + props: { + text: { + type: String, + }, + }, + template: '
{{text}}
', + }, + { + props: { + text: 'This is a very long text that should be truncated', + }, + global: { + directives: { + n8nTruncate, + }, + }, + }, + ); + expect(html()).toBe('
This is a very long text that...
'); + }); + + it('should truncate text to given length', async () => { + const { html } = render( + { + props: { + text: { + type: String, + }, + }, + template: '
{{text}}
', + }, + { + props: { + text: 'This is a very long text that should be truncated', + }, + global: { + directives: { + n8nTruncate, + }, + }, + }, + ); + expect(html()).toBe('
This is a very long text...
'); + }); +}); diff --git a/packages/design-system/src/directives/n8n-truncate.ts b/packages/design-system/src/directives/n8n-truncate.ts new file mode 100644 index 0000000000..8d454654c0 --- /dev/null +++ b/packages/design-system/src/directives/n8n-truncate.ts @@ -0,0 +1,26 @@ +import type { DirectiveBinding, ObjectDirective } from 'vue'; +import { truncate } from '../utils/string'; + +/** + * Custom directive `n8nTruncate` to truncate text content of an HTML element. + * + * Usage: + * In your Vue template, use the directive `v-n8n-truncate` with an argument to specify the length to truncate to. + * + * Example: + *

Some long text that will be truncated

+ * + * This will truncate the text content of the paragraph to 10 characters. + * + * Hint: Do not use it on components + * https://vuejs.org/guide/reusability/custom-directives#usage-on-components + */ + +export const n8nTruncate: ObjectDirective = { + mounted(el: HTMLElement, binding: DirectiveBinding) { + el.textContent = truncate(el.textContent ?? '', Number(binding.arg) || undefined); + }, + updated(el: HTMLElement, binding: DirectiveBinding) { + el.textContent = truncate(el.textContent ?? '', Number(binding.arg) || undefined); + }, +}; diff --git a/packages/design-system/src/main.ts b/packages/design-system/src/main.ts index 54934d6f1c..dddb89f888 100644 --- a/packages/design-system/src/main.ts +++ b/packages/design-system/src/main.ts @@ -5,4 +5,5 @@ export * from './components'; export * from './plugin'; export * from './types'; export * from './utils'; +export * from './directives'; export { locale }; diff --git a/packages/design-system/src/plugin.ts b/packages/design-system/src/plugin.ts index 493fde38ec..c6d3d2a6c9 100644 --- a/packages/design-system/src/plugin.ts +++ b/packages/design-system/src/plugin.ts @@ -1,5 +1,6 @@ import type { Component, Plugin } from 'vue'; import * as components from './components'; +import * as directives from './directives'; export interface N8nPluginOptions {} @@ -8,5 +9,9 @@ export const N8nPlugin: Plugin = { for (const [name, component] of Object.entries(components)) { app.component(name, component as unknown as Component); } + + for (const [name, directive] of Object.entries(directives)) { + app.directive(name, directive); + } }, }; diff --git a/packages/design-system/src/utils/string.test.ts b/packages/design-system/src/utils/string.test.ts new file mode 100644 index 0000000000..6f65775f9a --- /dev/null +++ b/packages/design-system/src/utils/string.test.ts @@ -0,0 +1,17 @@ +import { truncate } from './string'; + +describe('Utils string', () => { + describe('truncate', () => { + it('should truncate text to 30 chars by default', () => { + expect(truncate('This is a very long text that should be truncated')).toBe( + 'This is a very long text that...', + ); + }); + + it('should truncate text to given length', () => { + expect(truncate('This is a very long text that should be truncated', 25)).toBe( + 'This is a very long text...', + ); + }); + }); +}); diff --git a/packages/design-system/src/utils/string.ts b/packages/design-system/src/utils/string.ts new file mode 100644 index 0000000000..9170b57c00 --- /dev/null +++ b/packages/design-system/src/utils/string.ts @@ -0,0 +1,2 @@ +export const truncate = (text: string, length = 30): string => + text.length > length ? text.slice(0, length).trim() + '...' : text;