tiptapify 0.3.2 → 0.3.4

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 (87) hide show
  1. package/README.md +1 -0
  2. package/dist/tiptapify.css +1 -1
  3. package/dist/tiptapify.mjs +54477 -48112
  4. package/dist/tiptapify.umd.js +68 -68
  5. package/index.d.ts +96 -0
  6. package/package.json +2 -1
  7. package/src/components/Footer.vue +12 -2
  8. package/src/components/ImageBubbleMenu.vue +139 -0
  9. package/src/components/MenuBubble.vue +60 -7
  10. package/src/components/SkinScope.test.ts +74 -0
  11. package/src/components/SkinScope.vue +18 -0
  12. package/src/components/Tiptapify.skin.test.ts +186 -0
  13. package/src/components/Tiptapify.vue +285 -74
  14. package/src/components/Toolbar/Index.test.ts +96 -0
  15. package/src/components/Toolbar/Index.vue +199 -14
  16. package/src/components/Toolbar/Items.test.ts +82 -2
  17. package/src/components/Toolbar/Items.vue +104 -19
  18. package/src/components/Toolbar/alignment.ts +5 -0
  19. package/src/components/UI/TiptapifyDialog.test.ts +132 -0
  20. package/src/components/UI/TiptapifyDialog.vue +128 -12
  21. package/src/components/editorExtensions.test.ts +10 -0
  22. package/src/components/editorExtensions.ts +34 -5
  23. package/src/components/index.ts +3 -2
  24. package/src/composables/useTiptapifyConfig.test.ts +25 -2
  25. package/src/composables/useTiptapifyConfig.ts +21 -2
  26. package/src/constants/defaults.ts +2 -1
  27. package/src/extensions/components/actions/redo/Button.vue +1 -1
  28. package/src/extensions/components/actions/undo/Button.vue +1 -1
  29. package/src/extensions/components/alignment/menu/Button.vue +72 -0
  30. package/src/extensions/components/list/bullet/Button.vue +35 -16
  31. package/src/extensions/components/list/numbered/Button.vue +19 -0
  32. package/src/extensions/components/list/styles/ListStyleButton.vue +156 -0
  33. package/src/extensions/components/list/styles/index.ts +76 -0
  34. package/src/extensions/components/list/styles/listStyle.test.ts +44 -0
  35. package/src/extensions/components/media/image/ImageDialog.vue +1 -1
  36. package/src/extensions/components/media/image/caption.test.ts +122 -0
  37. package/src/extensions/components/media/image/caption.ts +268 -0
  38. package/src/extensions/components/media/image/slider.test.ts +106 -0
  39. package/src/extensions/components/media/image/slider.ts +87 -0
  40. package/src/extensions/components/style/heading/Button.vue +45 -30
  41. package/src/i18n/locales/ar.json +22 -0
  42. package/src/i18n/locales/bg.json +22 -0
  43. package/src/i18n/locales/ch.json +22 -0
  44. package/src/i18n/locales/cz.json +22 -0
  45. package/src/i18n/locales/de.json +22 -0
  46. package/src/i18n/locales/el.json +22 -0
  47. package/src/i18n/locales/en.json +23 -1
  48. package/src/i18n/locales/es.json +22 -0
  49. package/src/i18n/locales/et.json +22 -0
  50. package/src/i18n/locales/fi.json +22 -0
  51. package/src/i18n/locales/fr.json +22 -0
  52. package/src/i18n/locales/he.json +22 -0
  53. package/src/i18n/locales/hi.json +22 -0
  54. package/src/i18n/locales/hr.json +22 -0
  55. package/src/i18n/locales/hu.json +22 -0
  56. package/src/i18n/locales/id.json +22 -0
  57. package/src/i18n/locales/it.json +22 -0
  58. package/src/i18n/locales/ja.json +22 -0
  59. package/src/i18n/locales/ko.json +22 -0
  60. package/src/i18n/locales/la.json +22 -0
  61. package/src/i18n/locales/lt.json +22 -0
  62. package/src/i18n/locales/nl.json +22 -0
  63. package/src/i18n/locales/no.json +22 -0
  64. package/src/i18n/locales/pl.json +22 -0
  65. package/src/i18n/locales/pt-BR.json +22 -0
  66. package/src/i18n/locales/pt.json +22 -0
  67. package/src/i18n/locales/ro.json +22 -0
  68. package/src/i18n/locales/ru.json +23 -1
  69. package/src/i18n/locales/se.json +22 -0
  70. package/src/i18n/locales/sk.json +22 -0
  71. package/src/i18n/locales/sl.json +22 -0
  72. package/src/i18n/locales/sr.json +22 -0
  73. package/src/i18n/locales/th.json +22 -0
  74. package/src/i18n/locales/tr.json +22 -0
  75. package/src/i18n/locales/uk.json +23 -1
  76. package/src/i18n/locales/vi.json +22 -0
  77. package/src/index.test.ts +88 -0
  78. package/src/index.ts +15 -0
  79. package/src/skins/__fixtures__/skin-baseline.json +805 -0
  80. package/src/skins/builtins.ts +81 -0
  81. package/src/skins/menu.css +87 -0
  82. package/src/skins/menu.ts +10 -0
  83. package/src/skins/registry.test.ts +180 -0
  84. package/src/skins/registry.ts +132 -0
  85. package/src/skins/tokens.reachability.test.ts +43 -0
  86. package/src/skins/tokens.ts +92 -0
  87. package/src/types/editor.ts +99 -0
@@ -65,6 +65,8 @@
65
65
  },
66
66
  "image": {
67
67
  "alt": "ข้อความทางเลือก",
68
+ "caption": "คำบรรยายภาพ",
69
+ "caption_placeholder": "เพิ่มคำบรรยายภาพ…",
68
70
  "dialog_title": "เพิ่ม/แก้ไขรูปภาพ",
69
71
  "height": "ความสูง",
70
72
  "keep_ratio": "รักษาสัดส่วน",
@@ -121,6 +123,16 @@
121
123
  "indent": "เพิ่มการเยื้อง",
122
124
  "numbered": "รายการแบบมีหมายเลข",
123
125
  "outdent": "ลดการเยื้อง",
126
+ "styles": {
127
+ "circle": "Circle",
128
+ "default": "Default",
129
+ "lower_alpha": "Lower alpha",
130
+ "lower_greek": "Lower Greek",
131
+ "lower_roman": "Lower Roman",
132
+ "square": "Square",
133
+ "upper_alpha": "Upper alpha",
134
+ "upper_roman": "Upper Roman"
135
+ },
124
136
  "task": "รายการงาน"
125
137
  },
126
138
  "media": {
@@ -161,7 +173,17 @@
161
173
  },
162
174
  "iframe": "กรอบฝังตัว",
163
175
  "image": "รูปภาพ",
176
+ "image_toolbar": {
177
+ "align_left": "Align left",
178
+ "align_right": "Align right",
179
+ "delete": "Remove",
180
+ "download": "Download",
181
+ "edit": "Edit or replace",
182
+ "move_back": "Move one slide back",
183
+ "move_forward": "Move one slide forward"
184
+ },
164
185
  "link": "ลิงก์ภายนอก",
186
+ "slider": "สไลด์",
165
187
  "tables": {
166
188
  "col": "คอลัมน์",
167
189
  "cols": "คอลัมน์",
@@ -65,6 +65,8 @@
65
65
  },
66
66
  "image": {
67
67
  "alt": "Alternatif metin",
68
+ "caption": "Açıklama",
69
+ "caption_placeholder": "Açıklama ekleyin…",
68
70
  "dialog_title": "Görsel ekle/düzenle",
69
71
  "height": "Yükseklik",
70
72
  "keep_ratio": "En boy oranını koru",
@@ -121,6 +123,16 @@
121
123
  "indent": "Girintiyi artır",
122
124
  "numbered": "Numaralı liste",
123
125
  "outdent": "Girintiyi azalt",
126
+ "styles": {
127
+ "circle": "Circle",
128
+ "default": "Default",
129
+ "lower_alpha": "Lower alpha",
130
+ "lower_greek": "Lower Greek",
131
+ "lower_roman": "Lower Roman",
132
+ "square": "Square",
133
+ "upper_alpha": "Upper alpha",
134
+ "upper_roman": "Upper Roman"
135
+ },
124
136
  "task": "Görev listesi"
125
137
  },
126
138
  "media": {
@@ -161,7 +173,17 @@
161
173
  },
162
174
  "iframe": "iframe",
163
175
  "image": "Görsel",
176
+ "image_toolbar": {
177
+ "align_left": "Align left",
178
+ "align_right": "Align right",
179
+ "delete": "Remove",
180
+ "download": "Download",
181
+ "edit": "Edit or replace",
182
+ "move_back": "Move one slide back",
183
+ "move_forward": "Move one slide forward"
184
+ },
164
185
  "link": "Harici bağlantı",
186
+ "slider": "Slayt",
165
187
  "tables": {
166
188
  "col": "Sütun",
167
189
  "cols": "Sütunlar",
@@ -65,10 +65,12 @@
65
65
  },
66
66
  "image": {
67
67
  "alt": "alt",
68
+ "caption": "Підпис",
69
+ "caption_placeholder": "Додайте підпис…",
68
70
  "dialog_title": "Додавання/зміна зображення",
69
71
  "height": "Висота",
70
72
  "keep_ratio": "Зберігати пропорції",
71
- "src": "Джерело",
73
+ "src": "Адреса зображення",
72
74
  "title": "Заголовок",
73
75
  "width": "Ширина"
74
76
  },
@@ -121,6 +123,16 @@
121
123
  "indent": "Збільшити відступ елемента списку",
122
124
  "numbered": "Нумерований список",
123
125
  "outdent": "Зменшити відступ елемента списку",
126
+ "styles": {
127
+ "circle": "Коло",
128
+ "default": "Типовий",
129
+ "lower_alpha": "Малі літери",
130
+ "lower_greek": "Грецькі літери",
131
+ "lower_roman": "Малі римські",
132
+ "square": "Квадрат",
133
+ "upper_alpha": "Великі літери",
134
+ "upper_roman": "Великі римські"
135
+ },
124
136
  "task": "Список задач"
125
137
  },
126
138
  "media": {
@@ -161,7 +173,17 @@
161
173
  },
162
174
  "iframe": "iframe",
163
175
  "image": "Зображення",
176
+ "image_toolbar": {
177
+ "align_left": "Ліворуч, з обтіканням",
178
+ "align_right": "Праворуч, з обтіканням",
179
+ "delete": "Видалити",
180
+ "download": "Завантажити",
181
+ "edit": "Змінити або замінити",
182
+ "move_back": "На місце раніше",
183
+ "move_forward": "На місце пізніше"
184
+ },
164
185
  "link": "Зовнішнє посилання",
186
+ "slider": "Слайдер",
165
187
  "tables": {
166
188
  "col": "Стовпчик",
167
189
  "cols": "Стовпчики",
@@ -65,6 +65,8 @@
65
65
  },
66
66
  "image": {
67
67
  "alt": "Văn bản thay thế",
68
+ "caption": "Chú thích",
69
+ "caption_placeholder": "Thêm chú thích…",
68
70
  "dialog_title": "Thêm/sửa hình ảnh",
69
71
  "height": "Chiều cao",
70
72
  "keep_ratio": "Giữ tỷ lệ khung hình",
@@ -121,6 +123,16 @@
121
123
  "indent": "Tăng thụt đầu dòng",
122
124
  "numbered": "Danh sách có đánh số",
123
125
  "outdent": "Giảm thụt đầu dòng",
126
+ "styles": {
127
+ "circle": "Circle",
128
+ "default": "Default",
129
+ "lower_alpha": "Lower alpha",
130
+ "lower_greek": "Lower Greek",
131
+ "lower_roman": "Lower Roman",
132
+ "square": "Square",
133
+ "upper_alpha": "Upper alpha",
134
+ "upper_roman": "Upper Roman"
135
+ },
124
136
  "task": "Danh sách công việc"
125
137
  },
126
138
  "media": {
@@ -161,7 +173,17 @@
161
173
  },
162
174
  "iframe": "khung nhúng",
163
175
  "image": "Hình ảnh",
176
+ "image_toolbar": {
177
+ "align_left": "Align left",
178
+ "align_right": "Align right",
179
+ "delete": "Remove",
180
+ "download": "Download",
181
+ "edit": "Edit or replace",
182
+ "move_back": "Move one slide back",
183
+ "move_forward": "Move one slide forward"
184
+ },
164
185
  "link": "Liên kết ngoài",
186
+ "slider": "Trình chiếu",
165
187
  "tables": {
166
188
  "col": "Cột",
167
189
  "cols": "Cột",
@@ -0,0 +1,88 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { describe, expect, it } from 'vitest'
4
+ import { registerSkin, defineSkin } from '@tiptapify/index'
5
+ import { registerSkin as fromRegistry, defineSkin as defineFromRegistry } from '@tiptapify/skins/registry'
6
+
7
+ describe('package entry exports', () => {
8
+ it('exports registerSkin and defineSkin as functions', () => {
9
+ expect(typeof registerSkin).toBe('function')
10
+ expect(typeof defineSkin).toBe('function')
11
+ })
12
+
13
+ it('re-exports the registry functions, not copies', () => {
14
+ expect(registerSkin).toBe(fromRegistry)
15
+ expect(defineSkin).toBe(defineFromRegistry)
16
+ })
17
+
18
+ it('defineSkin is identity: the same object comes back', () => {
19
+ const skin = { extends: 'pastel', colors: { toolbarBg: 'rebeccapurple' } }
20
+
21
+ expect(defineSkin(skin)).toBe(skin)
22
+ })
23
+ })
24
+
25
+ describe('index.d.ts skin-type parity with src/types/editor.ts', () => {
26
+ // index.d.ts is hand-mirrored from the source types; this guard compares the
27
+ // exported skin-type declarations member-for-member (declared shape, not
28
+ // comments/formatting), ending the silent-drift risk of the hand mirror.
29
+ const SKIN_TYPES = [
30
+ 'TiptapifySkin',
31
+ 'TiptapifyShape',
32
+ 'ResolvedShape',
33
+ 'TiptapifySkinColors',
34
+ 'TiptapifySkinMetrics',
35
+ 'TiptapifySkinConfig',
36
+ 'TiptapifySkinInput',
37
+ ]
38
+
39
+ // cwd is the vitest root (the repo): the guard pins files of the package root
40
+ const dts = readFileSync(path.resolve(process.cwd(), 'index.d.ts'), 'utf8')
41
+ const source = readFileSync(path.resolve(process.cwd(), 'src/types/editor.ts'), 'utf8')
42
+
43
+ // The declaration block of `name`: a brace body to its closing brace,
44
+ // an alias body (no `{` on the header line) to the end of its line.
45
+ // Constraints of this extractor, adequate for the skin blocks it pins:
46
+ // declarations must be single-line aliases or brace-bodied types (the
47
+ // index.d.ts mirror style); the `//`-stripping in normalize treats any
48
+ // `//` as a comment start, so these blocks must contain no URLs in strings.
49
+ function declaration (file: string, name: string): string {
50
+ const lines = file.split('\n')
51
+ const start = lines.findIndex((line) => new RegExp(`^export (interface|type) ${name}\\b`).test(line))
52
+ if (start < 0) return ''
53
+ if (lines[start].indexOf('{') < 0) return lines[start]
54
+ let depth = 0
55
+ for (let i = start; i < lines.length; i++) {
56
+ for (const ch of lines[i]) {
57
+ if (ch === '{') depth++
58
+ if (ch === '}') depth--
59
+ }
60
+ if (depth === 0) return lines.slice(start, i + 1).join('\n')
61
+ }
62
+ return ''
63
+ }
64
+
65
+ // Tolerant to the formatting freedom of a hand-written mirror: interface vs type
66
+ // literal, comments, indentation, line breaks inside the body
67
+ function normalize (block: string, name: string): string {
68
+ return block
69
+ .split('\n')
70
+ .map((line) => line.replace(/\/\/.*$/, ''))
71
+ .join(' ')
72
+ .replace(new RegExp(`interface ${name} \\{`), `${name} {`)
73
+ .replace(new RegExp(`type ${name} = \\{`), `${name} {`)
74
+ .replace(/\s+/g, ' ')
75
+ .trim()
76
+ }
77
+
78
+ for (const name of SKIN_TYPES) {
79
+ it(`${name} is mirrored member-for-member`, () => {
80
+ const inDts = declaration(dts, name)
81
+ const inSource = declaration(source, name)
82
+
83
+ expect(inDts, `${name} missing from index.d.ts`).not.toBe('')
84
+ expect(inSource, `${name} missing from src/types/editor.ts`).not.toBe('')
85
+ expect(normalize(inDts, name)).toBe(normalize(inSource, name))
86
+ })
87
+ }
88
+ })
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import TiptapifyDialog from '@tiptapify/components/UI/TiptapifyDialog.vue'
4
4
  import { useTiptapifyConfig } from '@tiptapify/composables/useTiptapifyConfig'
5
5
  import { TiptapifyFooterAlignment } from '@tiptapify/types/editor'
6
6
  import { createAiBackendProvider } from '@tiptapify/extensions/components/ai/backend'
7
+ import { registerSkin, defineSkin } from '@tiptapify/skins/registry'
7
8
 
8
9
  import { Editor as TipTapEditor, nodeViewProps, NodeViewWrapper, VueNodeViewRenderer } from '@tiptap/vue-3'
9
10
  import { Node, Mark, markInputRule, markPasteRule, mergeAttributes } from '@tiptap/core'
@@ -13,6 +14,9 @@ import * as mdi from '@mdi/js'
13
14
 
14
15
  import { messages } from './i18n'
15
16
 
17
+ // The shared menu skin stylesheet: shipped in the dist CSS next to the SFC styles (spec: Menu CSS strategy)
18
+ import './skins/menu.css'
19
+
16
20
  interface PackageOptions {
17
21
  i18n?: any;
18
22
  }
@@ -46,11 +50,22 @@ export {
46
50
  markInputRule,
47
51
  markPasteRule,
48
52
  mergeAttributes,
53
+ registerSkin,
54
+ defineSkin,
49
55
  }
50
56
 
51
57
  export type { TiptapifyConfig } from '@tiptapify/composables/useTiptapifyConfig'
52
58
  export type { TiptapifyFooterAlignment }
53
59
  export type { CommandProps, InputRuleMatch, PasteRuleMatch }
60
+ export type {
61
+ TiptapifySkin,
62
+ TiptapifyShape,
63
+ TiptapifySkinColors,
64
+ TiptapifySkinMetrics,
65
+ TiptapifySkinConfig,
66
+ TiptapifySkinInput,
67
+ ResolvedShape,
68
+ } from '@tiptapify/types/editor'
54
69
  export type {
55
70
  TiptapifyAiBackendProviderOptions,
56
71
  TiptapifyAiBackendRequest,