tiptapify 0.0.5 → 0.0.7

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 (43) hide show
  1. package/README.md +7 -1
  2. package/dist/tiptapify.css +1 -1
  3. package/dist/{tiptapify.es.js → tiptapify.mjs} +52867 -51790
  4. package/dist/tiptapify.umd.js +41 -43
  5. package/package.json +8 -8
  6. package/src/components/Footer.vue +5 -6
  7. package/src/components/MenuBubble.vue +61 -47
  8. package/src/components/MenuFloating.vue +38 -34
  9. package/src/components/Tiptapify.vue +139 -23
  10. package/src/components/Toolbar/Group.vue +43 -0
  11. package/src/components/Toolbar/GroupDropdown.vue +85 -0
  12. package/src/components/Toolbar/Index.vue +51 -79
  13. package/src/components/Toolbar/Toggle.vue +33 -0
  14. package/src/components/Toolbar/items/actions.ts +32 -0
  15. package/src/components/Toolbar/items/alignment.ts +60 -0
  16. package/src/components/Toolbar/items/format.ts +73 -0
  17. package/src/components/Toolbar/items/formatExtra.ts +73 -0
  18. package/src/components/Toolbar/items/list.ts +70 -0
  19. package/src/components/Toolbar/items/media.ts +202 -0
  20. package/src/components/Toolbar/items/misc.ts +59 -0
  21. package/src/components/Toolbar/items/style.ts +146 -0
  22. package/src/components/Toolbar/items.ts +73 -545
  23. package/src/components/editorExtensions.ts +6 -4
  24. package/src/components/index.ts +13 -0
  25. package/src/{components/extensions → extensions}/components/LinkDialog.vue +11 -8
  26. package/src/extensions/components/PreviewDialog.vue +45 -0
  27. package/src/{components/extensions/components/ShowSource.vue → extensions/components/ShowSourceDialog.vue} +11 -7
  28. package/src/extensions/components/TableBuilder.vue +138 -0
  29. package/src/extensions/preview.ts +53 -0
  30. package/src/{components/extensions → extensions}/view-source.ts +1 -3
  31. package/src/i18n/locales/de.json +64 -45
  32. package/src/i18n/locales/en.json +21 -2
  33. package/src/i18n/locales/es.json +27 -8
  34. package/src/i18n/locales/fr.json +26 -7
  35. package/src/i18n/locales/it.json +36 -17
  36. package/src/i18n/locales/pl.json +28 -9
  37. package/src/i18n/locales/ru.json +21 -2
  38. package/src/i18n/locales/ua.json +21 -2
  39. package/src/utils/helpers.ts +17 -0
  40. package/src/composable/useEditor.ts +0 -35
  41. /package/src/{components/extensions → extensions}/components/slashCommands/CommandsList.vue +0 -0
  42. /package/src/{components/extensions → extensions}/components/slashCommands/suggestion.ts +0 -0
  43. /package/src/{components/extensions → extensions}/slash-commands.ts +0 -0
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "tiptapify",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Tiptap3 editor with Vuetify3 menu implementation",
5
5
  "exports": {
6
6
  ".": {
7
7
  "import": {
8
- "default": "./dist/tiptapify.es.js",
8
+ "default": "./dist/tiptapify.mjs",
9
9
  "development": "./src/index.ts"
10
10
  },
11
11
  "require": {
@@ -18,7 +18,7 @@
18
18
  "./style.css": "./dist/tiptapify.css"
19
19
  },
20
20
  "main": "./dist/tiptapify.umd.cjs",
21
- "module": "./dist/tiptapify.js",
21
+ "module": "./dist/tiptapify.mjs",
22
22
  "source": "./src/index.ts",
23
23
  "files": [
24
24
  "dist",
@@ -49,7 +49,7 @@
49
49
  "author": "Igor Voytovich",
50
50
  "license": "MIT",
51
51
  "repository": "https://github.com/IVoyt/tiptapify",
52
- "packageManager": "pnpm@10.11.0",
52
+ "packageManager": "pnpm@10.11.1",
53
53
  "dependencies": {
54
54
  "@tiptap/core": "next",
55
55
  "@tiptap/extension-blockquote": "next",
@@ -92,7 +92,7 @@
92
92
  "highlight.js": "^11.11.1",
93
93
  "linkifyjs": "^4.3.1",
94
94
  "lowlight": "^3.3.0",
95
- "vue-i18n": "^11.1.4"
95
+ "vue-i18n": "^11.1.5"
96
96
  },
97
97
  "peerDependencies": {
98
98
  "@mdi/js": "^7.4.47",
@@ -102,13 +102,13 @@
102
102
  "devDependencies": {
103
103
  "@intlify/unplugin-vue-i18n": "^6.0.8",
104
104
  "@rollup/plugin-alias": "^5.1.1",
105
- "@types/node": "^22.15.21",
105
+ "@types/node": "^22.15.30",
106
106
  "@vitejs/plugin-vue": "^5.2.4",
107
107
  "@vitejs/plugin-vue-jsx": "^4.2.0",
108
108
  "rollup-plugin-tsconfig-paths": "^1.5.2",
109
- "sass-embedded": "^1.89.0",
109
+ "sass-embedded": "^1.89.1",
110
110
  "typescript": "^5.8.3",
111
- "unplugin-vue-components": "^28.5.0",
111
+ "unplugin-vue-components": "^28.7.0",
112
112
  "vite": "^6.3.5",
113
113
  "vite-plugin-vuetify": "^2.1.1",
114
114
  "vite-svg-loader": "^5.1.0",
@@ -1,17 +1,16 @@
1
1
  <script setup lang="ts">
2
- import { useEditor } from "@tiptapify/composable/useEditor";
3
- import { ref } from 'vue'
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import { inject, Ref } from "vue";
4
4
 
5
- const { editor } = useEditor()
6
- const editorInstance = ref(editor.getInstance())
5
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
7
6
  </script>
8
7
 
9
8
  <template>
10
- <div v-if="editorInstance" class="tiptapify-footer">
9
+ <div v-if="editor" class="tiptapify-footer">
11
10
  <VRow>
12
11
  <VCol class="d-flex justify-end">
13
12
  <span class="words-count">
14
- {{ editorInstance.storage.characterCount.words() }} words
13
+ {{ editor.storage.characterCount.words() }} words
15
14
  </span>
16
15
  </VCol>
17
16
  </VRow>
@@ -1,16 +1,16 @@
1
1
  <script setup lang="ts">
2
- import LinkDialog from "@tiptapify/components/extensions/components/LinkDialog.vue";
3
- import { useEditor } from "@tiptapify/composable/useEditor";
4
- import { computed, defineProps, ref } from "vue";
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import LinkDialog from "@tiptapify/extensions/components/LinkDialog.vue";
4
+ import { computed, defineProps, inject, Ref, ref } from "vue";
5
5
  import { BubbleMenu } from '@tiptap/vue-3/menus'
6
6
  import * as mdi from '@mdi/js'
7
7
 
8
8
  defineProps({
9
9
  variant: { type: String, default () { return 'flat' }},
10
+ theme: { type: String, default () { return 'light' }},
10
11
  })
11
12
 
12
- const { editor } = useEditor()
13
- const editorInstance = ref(editor.getInstance())
13
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
14
14
 
15
15
  const bubbleMenuLinkButton = ref(null)
16
16
 
@@ -19,88 +19,105 @@ const items = ref([
19
19
  name: 'bold',
20
20
  icon: mdi.mdiFormatBold,
21
21
  props: {
22
- active: false,
23
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleBold().run()),
24
- color: computed(() => editorInstance.value.isActive('bold') ? 'primary' : ''),
22
+ disabled: computed(() => !editor?.value.can().chain().focus().toggleBold().run()),
23
+ color: computed(() => editor.value.isActive('bold') ? 'primary' : ''),
25
24
  },
26
- click: () => editorInstance.value.chain().focus().toggleBold().run(),
25
+ click: () => editor.value.chain().focus().toggleBold().run(),
27
26
  },
28
27
  {
29
28
  name: 'italic',
30
29
  icon: mdi.mdiFormatItalic,
31
30
  props: {
32
- active: false,
33
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleItalic().run()),
34
- color: computed(() => editorInstance.value.isActive('italic') ? 'primary' : ''),
31
+ disabled: computed(() => !editor.value.can().chain().focus().toggleItalic().run()),
32
+ color: computed(() => editor.value.isActive('italic') ? 'primary' : ''),
35
33
  },
36
- click: () => editorInstance.value.chain().focus().toggleItalic().run(),
34
+ click: () => editor.value.chain().focus().toggleItalic().run(),
37
35
  },
38
36
  {
39
37
  name: 'strike',
40
38
  icon: mdi.mdiFormatStrikethroughVariant,
41
39
  props: {
42
- active: false,
43
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleStrike().run()),
44
- color: computed(() => editorInstance.value.isActive('strike') ? 'primary' : ''),
40
+ disabled: computed(() => !editor.value.can().chain().focus().toggleStrike().run()),
41
+ color: computed(() => editor.value.isActive('strike') ? 'primary' : ''),
45
42
  },
46
- click: () => editorInstance.value.chain().focus().toggleStrike().run(),
43
+ click: () => editor.value.chain().focus().toggleStrike().run(),
47
44
  },
48
45
  {
49
46
  name: 'underline',
50
47
  icon: mdi.mdiFormatUnderline,
51
48
  props: {
52
- active: false,
53
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleUnderline().run()),
54
- color: computed(() => editorInstance.value.isActive('underline') ? 'primary' : ''),
49
+ disabled: computed(() => !editor.value.can().chain().focus().toggleUnderline().run()),
50
+ color: computed(() => editor.value.isActive('underline') ? 'primary' : ''),
55
51
  },
56
- click: () => editorInstance.value.chain().focus().toggleUnderline().run(),
52
+ click: () => editor.value.chain().focus().toggleUnderline().run(),
57
53
  },
58
54
  {
59
55
  name: 'highlight',
60
56
  icon: mdi.mdiFormatColorHighlight,
61
57
  props: {
62
- active: false,
63
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleHighlight().run()),
64
- color: computed(() => editorInstance.value.isActive('highlight') ? 'primary' : ''),
58
+ disabled: computed(() => !editor.value.can().chain().focus().toggleHighlight().run()),
59
+ color: computed(() => editor.value.isActive('highlight') ? 'primary' : ''),
65
60
  },
66
- click: () => editorInstance.value.chain().focus().toggleHighlight().run(),
61
+ click: () => editor.value.chain().focus().toggleHighlight().run(),
62
+ },
63
+ {
64
+ name: 'code',
65
+ icon: mdi.mdiXml,
66
+ props: {
67
+ disabled: computed(() => !editor.value.can().chain().focus().toggleCode().run()),
68
+ color: computed(() => editor.value.isActive('code') ? 'primary' : ''),
69
+ },
70
+ click: () => editor.value.chain().focus().toggleCode().run(),
67
71
  },
68
72
  {
69
73
  name: 'link',
70
- icon: computed(() => editorInstance.value.isActive('link') ? mdi.mdiLinkOff : mdi.mdiLink),
74
+ icon: computed(() => editor.value.isActive('link') ? mdi.mdiLinkOff : mdi.mdiLink),
71
75
  props: {
72
- active: false,
73
- color: computed(() => editorInstance.value.isActive('link') ? 'primary' : ''),
74
- disabled: computed(() => editorInstance.value.isActive('code') || editorInstance.value.isActive('codeBlock')),
76
+ color: computed(() => editor.value.isActive('link') ? 'primary' : ''),
77
+ disabled: computed(() => editor.value.isActive('code') || editor.value.isActive('codeBlock')),
75
78
  },
76
79
  click: () => linkAction(),
77
80
  },
78
81
  {
79
82
  name: 'format clear',
80
83
  icon: mdi.mdiFormatClear,
81
- props: {
82
- active: false,
83
- },
84
- click: () => editorInstance.value.chain().focus().unsetAllMarks().clearNodes().run(),
84
+ click: () => editor.value.chain().focus().unsetAllMarks().clearNodes().run(),
85
85
  }
86
86
  ])
87
87
 
88
88
  function linkAction() {
89
- return editorInstance.value.isActive('link')
90
- ? editorInstance.value.chain().focus().unsetLink().run()
89
+ return editor.value.isActive('link')
90
+ ? editor.value.chain().focus().unsetLink().run()
91
91
  : bubbleMenuLinkButton.value?.open()
92
92
  }
93
93
  </script>
94
94
 
95
95
  <template>
96
- <!-- <BubbleMenu v-if="editorInstance" :editor="editorInstance" :tippy-options="{ duration: 100 }">-->
97
- <BubbleMenu v-if="editorInstance" :editor="editorInstance" :options="{ placement: 'bottom' }">
96
+ <BubbleMenu
97
+ v-if="editor"
98
+ :editor="editor"
99
+ :options="{ placement: 'bottom' }"
100
+ :shouldShow="({ editor, view, state, from, to }) => {
101
+ const docSize = editor.state.doc.content.size
102
+ const isAllSelected = from === 0 && to === docSize
103
+
104
+ return (from !== to) && !isAllSelected
105
+ }"
106
+ >
98
107
  <div class="bubble-menu">
99
- <VBtnToggle divided density="compact" :variant="variant">
100
- <VBtn v-for="(item, key) in items" :key="key" v-bind="item.props" @click="item.click" size="small">
101
- <VIcon :icon="item.icon" size="16" />
102
- </VBtn>
103
- </VBtnToggle>
108
+ <VCard>
109
+ <VCardText class="pa-0">
110
+ <VToolbar :theme="theme" density="compact" height="auto" class="p-0">
111
+ <VToolbarItems>
112
+ <VBtnGroup divided density="compact">
113
+ <VBtn v-for="(item, key) in items" :key="key" v-bind="item.props" @click="item.click" size="x-small">
114
+ <VIcon :icon="item.icon" size="20" />
115
+ </VBtn>
116
+ </VBtnGroup>
117
+ </VToolbarItems>
118
+ </VToolbar>
119
+ </VCardText>
120
+ </VCard>
104
121
  </div>
105
122
  </BubbleMenu>
106
123
 
@@ -109,10 +126,7 @@ function linkAction() {
109
126
 
110
127
  <style scoped lang="scss">
111
128
  .bubble-menu {
112
- border-radius: 4px;
113
- border-color: var(--gray-3);
114
- border-style: solid;
115
- border-width: 1px;
116
- box-shadow: var(--shadow);
129
+ border-radius: 6px;
130
+ box-shadow: 4px 4px 20px var(--dark-gray);
117
131
  }
118
132
  </style>
@@ -1,54 +1,58 @@
1
1
  <script setup lang="ts">
2
- import { useEditor } from "@tiptapify/composable/useEditor";
3
- import { defineProps, ref } from "vue";
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import { defineProps, inject, Ref } from "vue";
4
4
  import { FloatingMenu } from '@tiptap/vue-3/menus'
5
5
  import * as mdi from '@mdi/js'
6
6
 
7
7
  defineProps({
8
8
  variant: { type: String, default () { return '' }},
9
+ theme: { type: String, default () { return 'light' }},
9
10
  })
10
11
 
11
- const { editor } = useEditor()
12
- const editorInstance = ref(editor.getInstance())
12
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
13
13
  </script>
14
14
 
15
15
  <template>
16
- <!-- <FloatingMenu v-if="editorInstance" :editor="editorInstance" :tippy-options="{ duration: 100 }" >-->
17
- <FloatingMenu v-if="editorInstance" :editor="editorInstance">
16
+ <FloatingMenu v-if="editor" :editor="editor">
18
17
  <div class="floating-menu">
19
- <VBtnToggle divided density="compact" :variant="`${variant || 'plain'}`">
20
- <VBtn
21
- @click="editorInstance.chain().focus().toggleHeading({ level: 1 }).run()"
22
- :color="`${editorInstance.isActive('heading', { level: 1 }) ? 'primary' : ''}`"
23
- size="small"
24
- >
25
- <VIcon :icon="mdi['mdiFormatHeader1']" size="16" />
26
- </VBtn>
27
- <VBtn
28
- @click="editorInstance.chain().focus().toggleHeading({ level: 2 }).run()"
29
- :color="`${editorInstance.isActive('heading', { level: 2 }) ? 'primary' : ''}`"
30
- size="small"
31
- >
32
- <VIcon :icon="mdi['mdiFormatHeader2']" size="16" />
33
- </VBtn>
34
- <VBtn
35
- @click="editorInstance.chain().focus().toggleBulletList().run()"
36
- :color="`${editorInstance.isActive('bulletList') ? 'primary' : ''}`"
37
- size="small"
38
- >
39
- <VIcon :icon="mdi['mdiFormatListBulleted']" size="16" />
40
- </VBtn>
41
- </VBtnToggle>
18
+ <VCard>
19
+ <VCardText class="pa-0">
20
+ <VToolbar :theme="theme" density="compact" height="auto" class="p-0">
21
+ <VToolbarItems>
22
+ <VBtnGroup divided density="compact">
23
+ <VBtn
24
+ @click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
25
+ :color="`${editor.isActive('heading', { level: 1 }) ? 'primary' : ''}`"
26
+ size="small"
27
+ >
28
+ <VIcon :icon="mdi['mdiFormatHeader1']" size="16" />
29
+ </VBtn>
30
+ <VBtn
31
+ @click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
32
+ :color="`${editor.isActive('heading', { level: 2 }) ? 'primary' : ''}`"
33
+ size="small"
34
+ >
35
+ <VIcon :icon="mdi['mdiFormatHeader2']" size="16" />
36
+ </VBtn>
37
+ <VBtn
38
+ @click="editor.chain().focus().toggleBulletList().run()"
39
+ :color="`${editor.isActive('bulletList') ? 'primary' : ''}`"
40
+ size="small"
41
+ >
42
+ <VIcon :icon="mdi['mdiFormatListBulleted']" size="16" />
43
+ </VBtn>
44
+ </VBtnGroup>
45
+ </VToolbarItems>
46
+ </VToolbar>
47
+ </VCardText>
48
+ </VCard>
42
49
  </div>
43
50
  </FloatingMenu>
44
51
  </template>
45
52
 
46
53
  <style scoped lang="scss">
47
54
  .floating-menu {
48
- border-radius: 4px;
49
- border-color: var(--gray-3);
50
- border-style: solid;
51
- border-width: 1px;
52
- box-shadow: var(--shadow);
55
+ border-radius: 6px;
56
+ box-shadow: 4px 4px 20px var(--dark-gray);
53
57
  }
54
58
  </style>
@@ -1,17 +1,19 @@
1
1
  <script setup lang="ts">
2
2
 
3
- import { onBeforeUnmount, ref } from "vue";
3
+ import { onBeforeUnmount, provide, ref, ShallowRef, shallowRef, watch } from "vue";
4
4
  import { default as Toolbar } from "@tiptapify/components/Toolbar/Index.vue";
5
- import { EditorContent } from '@tiptap/vue-3'
6
- import { useEditor } from '@tiptapify/composable/useEditor'
5
+ import { Editor, EditorContent } from '@tiptap/vue-3'
7
6
  import MenuBubble from '@tiptapify/components/MenuBubble.vue'
8
7
  import MenuFloating from '@tiptapify/components/MenuFloating.vue'
9
8
 
9
+ import { getTiptapEditor } from "@tiptapify/components/index";
10
+
10
11
  import Footer from '@tiptapify/components/Footer.vue'
12
+ import { useTheme } from "vuetify/framework";
11
13
 
12
14
  const props = defineProps({
13
15
  content: String|Object,
14
- variant: { type: String, default () { return 'flat' } },
16
+ variant: { type: String, default () { return 'elevated' } },
15
17
  toolbar: { type: Boolean, default () { return true } },
16
18
  items: { type: Array<string>, default() { return [] }},
17
19
  itemsExclude: { type: Boolean, default() { return false } },
@@ -22,39 +24,59 @@ const props = defineProps({
22
24
  showCharacterCount: { type: Boolean, default () { return true } },
23
25
  defaultFontFamily: { type: String, default () { return 'Inter' } },
24
26
  fontMeasure: { type: String, default () { return 'px' } },
27
+ rounded: { type: String, default () { return '0' } },
25
28
  })
26
29
 
27
- const editor = useEditor(props.content, props.placeholder, props.slashCommands).editor
28
- const editorInstance = ref(editor.getInstance())
29
- editorInstance?.value?.chain().setFontFamily(props.defaultFontFamily).run()
30
+ const theme = ref(useTheme().current.value.dark ? 'dark' : 'light')
31
+
32
+ const editor: ShallowRef<Editor | undefined> = shallowRef(
33
+ getTiptapEditor(props.content, props.placeholder, props.slashCommands)
34
+ )
35
+
36
+ const emit = defineEmits(['update:modelValue', 'editor-ready']);
37
+
38
+ provide('tiptapifyEditor', editor)
39
+
40
+ editor.value?.chain().setFontFamily(props.defaultFontFamily).run()
41
+
42
+ defineExpose({ editor: editor });
43
+
44
+ watch(() => editor.value, (editorInstance) => {
45
+ if (editorInstance instanceof Editor) {
46
+ emit('editor-ready', {
47
+ getHTML: () => editorInstance.getHTML(),
48
+ getJSON: () => editorInstance.getJSON(),
49
+ });
50
+ }
51
+ }, { immediate: true });
30
52
 
31
53
  onBeforeUnmount(() => {
32
- editor.destroy()
54
+ editor.value?.destroy()
33
55
  })
34
-
35
56
  </script>
36
57
 
37
58
  <template>
38
59
  <VContainer>
39
60
  <VRow>
40
61
  <VCol>
41
- <div class="border rounded">
42
- <template v-if="toolbar">
43
- <Toolbar
44
- v-if="editorInstance"
45
- :variant="variant"
46
- :font-measure="fontMeasure"
47
- :items="items"
48
- :items-exclude="itemsExclude"
49
- />
50
- </template>
51
-
62
+ <template v-if="toolbar">
63
+ <Toolbar
64
+ v-if="editor"
65
+ :variant="variant"
66
+ :font-measure="fontMeasure"
67
+ :items="items"
68
+ :items-exclude="itemsExclude"
69
+ :rounded="rounded"
70
+ />
71
+ </template>
72
+
73
+ <div :class="`border border-t-0 rounded-b-${rounded}`">
52
74
  <div class="pa-2 tiptapify-container">
53
- <MenuFloating v-if="floatingMenu" />
75
+ <MenuFloating v-if="floatingMenu" :variant="variant" :theme="theme" />
54
76
 
55
- <MenuBubble v-if="bubbleMenu" />
77
+ <MenuBubble v-if="bubbleMenu" :variant="variant" :theme="theme" />
56
78
 
57
- <EditorContent :editor="editorInstance" class="tiptapify-editor" />
79
+ <EditorContent :editor="editor" class="tiptapify-editor" />
58
80
  </div>
59
81
 
60
82
  <template v-if="showCharacterCount">
@@ -77,6 +99,8 @@ onBeforeUnmount(() => {
77
99
  --white: #FFF;
78
100
  --black: #2E2B29;
79
101
  --black-contrast: #110F0E;
102
+ --dark-gray: rgb(98, 98, 98);
103
+ --gray: rgb(223 223 223);
80
104
  --gray-1: rgba(61, 37, 20, .05);
81
105
  --gray-2: rgba(61, 37, 20, .08);
82
106
  --gray-3: rgba(61, 37, 20, .12);
@@ -135,6 +159,36 @@ onBeforeUnmount(() => {
135
159
  }
136
160
  }
137
161
 
162
+ /* Task list specific styles */
163
+ ul[data-type='taskList'] {
164
+ list-style: none;
165
+ margin-left: 0;
166
+ padding: 0;
167
+
168
+ li {
169
+ align-items: flex-start;
170
+ display: flex;
171
+
172
+ > label {
173
+ flex: 0 0 auto;
174
+ margin-right: 0.5rem;
175
+ user-select: none;
176
+ }
177
+
178
+ > div {
179
+ flex: 1 1 auto;
180
+ }
181
+ }
182
+
183
+ input[type='checkbox'] {
184
+ cursor: pointer;
185
+ }
186
+
187
+ ul[data-type='taskList'] {
188
+ margin: 0;
189
+ }
190
+ }
191
+
138
192
  /* Heading styles */
139
193
  h1,
140
194
  h2,
@@ -260,5 +314,67 @@ onBeforeUnmount(() => {
260
314
  border-top: 1px solid var(--gray-2);
261
315
  margin: 2rem 0;
262
316
  }
317
+
318
+ /* Table-specific styling */
319
+ table {
320
+ border-collapse: collapse;
321
+ margin: 0;
322
+ overflow: hidden;
323
+ table-layout: fixed;
324
+ width: 100%;
325
+
326
+ td,
327
+ th {
328
+ border: 1px solid var(--gray-3);
329
+ box-sizing: border-box;
330
+ min-width: 1em;
331
+ padding: 6px 8px;
332
+ position: relative;
333
+ vertical-align: top;
334
+
335
+ > * {
336
+ margin-bottom: 0;
337
+ }
338
+ }
339
+
340
+ th {
341
+ background-color: var(--gray-1);
342
+ font-weight: bold;
343
+ text-align: left;
344
+ }
345
+
346
+ .selectedCell:after {
347
+ background: var(--gray-2);
348
+ content: '';
349
+ left: 0;
350
+ right: 0;
351
+ top: 0;
352
+ bottom: 0;
353
+ pointer-events: none;
354
+ position: absolute;
355
+ z-index: 2;
356
+ }
357
+
358
+ .column-resize-handle {
359
+ background-color: var(--purple);
360
+ bottom: -2px;
361
+ pointer-events: none;
362
+ position: absolute;
363
+ right: -2px;
364
+ top: 0;
365
+ width: 4px;
366
+ }
367
+ }
368
+
369
+ .tableWrapper {
370
+ margin: 1.5rem 0;
371
+ overflow-x: auto;
372
+ }
373
+
374
+ &.resize-cursor {
375
+ cursor: ew-resize;
376
+ cursor: col-resize;
377
+ }
378
+
263
379
  }
264
380
  </style>
@@ -0,0 +1,43 @@
1
+ <script setup lang="ts">
2
+ import GroupDropdown from "@tiptapify/components/Toolbar/GroupDropdown.vue";
3
+ import { defineProps, PropType } from 'vue'
4
+ import { useI18n } from "vue-i18n";
5
+
6
+ import { ToolbarItemSection } from "@tiptapify/components/Toolbar/items";
7
+
8
+ import helpers from "@tiptapify/utils/helpers";
9
+
10
+ defineProps({
11
+ variant: { type: String, default () { return 'flat' }},
12
+ section: { type: String, default() { return '' }},
13
+ toolbarSection: { type: Object as PropType<ToolbarItemSection>, default() { return {} }}
14
+ })
15
+
16
+ const { t } = useI18n();
17
+
18
+ const { ucFirst } = helpers;
19
+
20
+ </script>
21
+
22
+ <template>
23
+ <VBtnGroup :variant="variant" elevation="4">
24
+ <template v-for="(toolbarItem, toolbarItemKey) in toolbarSection.items" :key="toolbarItemKey">
25
+ <template v-if="toolbarItem.children">
26
+ <GroupDropdown :toolbar-item="toolbarItem" :variant="variant" />
27
+ </template>
28
+
29
+ <VBtn v-else v-bind="toolbarItem.props" v-on="toolbarItem.attrs" size="32">
30
+ <VTooltip :text="ucFirst(t(toolbarItem.tooltip))" location="top" activator="parent" />
31
+
32
+ <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
33
+ <span v-else class="menu-item-title">
34
+ {{ ucFirst(t(toolbarItem.name)) }}
35
+ </span>
36
+ </VBtn>
37
+ </template>
38
+ </VBtnGroup>
39
+ </template>
40
+
41
+ <style lang="scss" scoped>
42
+
43
+ </style>