@tiptap/extension-youtube 2.0.0-beta.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.
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # @tiptap/extension-youtube
2
+ [![Version](https://img.shields.io/npm/v/@tiptap/extension-youtube.svg?label=version)](https://www.npmjs.com/package/@tiptap/extension-youtube)
3
+ [![Downloads](https://img.shields.io/npm/dm/@tiptap/extension-youtube.svg)](https://npmcharts.com/compare/tiptap?minimal=true)
4
+ [![License](https://img.shields.io/npm/l/@tiptap/extension-youtube.svg)](https://www.npmjs.com/package/@tiptap/extension-youtube)
5
+ [![Sponsor](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub)](https://github.com/sponsors/ueberdosis)
6
+
7
+ ## Introduction
8
+ Tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) – a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*.
9
+
10
+ ## Official Documentation
11
+ Documentation can be found on the [tiptap website](https://tiptap.dev).
12
+
13
+ ## License
14
+ Tiptap is open sourced software licensed under the [MIT license](https://github.com/ueberdosis/tiptap/blob/main/LICENSE.md).
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@tiptap/extension-youtube",
3
+ "description": "a youtube embed extension for tiptap",
4
+ "version": "2.0.0-beta.4",
5
+ "homepage": "https://tiptap.dev",
6
+ "keywords": [
7
+ "tiptap",
8
+ "tiptap extension"
9
+ ],
10
+ "license": "MIT",
11
+ "funding": {
12
+ "type": "github",
13
+ "url": "https://github.com/sponsors/ueberdosis"
14
+ },
15
+ "main": "dist/tiptap-extension-video.cjs.js",
16
+ "umd": "dist/tiptap-extension-video.umd.js",
17
+ "module": "dist/tiptap-extension-video.esm.js",
18
+ "types": "dist/packages/extension-video/src/index.d.ts",
19
+ "files": [
20
+ "src",
21
+ "dist"
22
+ ],
23
+ "peerDependencies": {
24
+ "@tiptap/core": "^2.0.0-beta.1"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/ueberdosis/tiptap.git",
29
+ "directory": "packages/extension-video"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/ueberdosis/tiptap/issues"
33
+ },
34
+ "scripts": {
35
+ "test": "echo \"Error: no test specified\" && exit 1"
36
+ },
37
+ "author": ""
38
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { Youtube } from './youtube'
2
+
3
+ export * from './youtube'
4
+
5
+ export default Youtube
package/src/utils.ts ADDED
@@ -0,0 +1,63 @@
1
+ export const isValidYoutubeUrl = (url: string) => {
2
+ return url.match(/^(https?:\/\/)?(www\.|music\.)?(youtube\.com|youtu\.be)(.+)?$/)
3
+ }
4
+
5
+ export interface GetEmbedUrlOptions {
6
+ url: string;
7
+ controls?: boolean;
8
+ nocookie?: boolean;
9
+ startAt?: number;
10
+ }
11
+
12
+ export const getYoutubeEmbedUrl = (nocookie?: boolean) => {
13
+ return nocookie ? 'https://www.youtube-nocookie.com/embed/' : 'https://www.youtube.com/embed/'
14
+ }
15
+
16
+ export const getEmbedURLFromYoutubeURL = (options: GetEmbedUrlOptions) => {
17
+ const {
18
+ url,
19
+ controls,
20
+ nocookie,
21
+ startAt,
22
+ } = options
23
+
24
+ // if is already an embed url, return it
25
+ if (url.includes('/embed/')) {
26
+ return url
27
+ }
28
+
29
+ // if is a youtu.be url, get the id after the /
30
+ if (url.includes('youtu.be')) {
31
+ const id = url.split('/').pop()
32
+
33
+ if (!id) {
34
+ return null
35
+ }
36
+ return `${getYoutubeEmbedUrl(nocookie)}${id}`
37
+ }
38
+
39
+ const videoIdRegex = /v=([-\w]+)/gm
40
+ const matches = videoIdRegex.exec(url)
41
+
42
+ if (!matches || !matches[1]) {
43
+ return null
44
+ }
45
+
46
+ let outputUrl = `${getYoutubeEmbedUrl(nocookie)}${matches[1]}`
47
+
48
+ const params = []
49
+
50
+ if (!controls) {
51
+ params.push('controls=0')
52
+ }
53
+
54
+ if (startAt) {
55
+ params.push(`start=${startAt}`)
56
+ }
57
+
58
+ if (params.length) {
59
+ outputUrl += `?${params.join('&')}`
60
+ }
61
+
62
+ return outputUrl
63
+ }
package/src/youtube.ts ADDED
@@ -0,0 +1,118 @@
1
+ import { mergeAttributes, Node } from '@tiptap/core'
2
+
3
+ import { getEmbedURLFromYoutubeURL, isValidYoutubeUrl } from './utils'
4
+
5
+ export interface YoutubeOptions {
6
+ inline: boolean;
7
+ width: number;
8
+ height: number;
9
+ controls: boolean;
10
+ nocookie: boolean;
11
+ allowFullscreen: boolean;
12
+ HTMLAttributes: Record<string, any>,
13
+ }
14
+
15
+ declare module '@tiptap/core' {
16
+ interface Commands<ReturnType> {
17
+ youtube: {
18
+ /**
19
+ * Insert a youtube video
20
+ */
21
+ setYoutubeVideo: (options: { src: string, width?: number, height?: number, start?: number }) => ReturnType,
22
+ }
23
+ }
24
+ }
25
+
26
+ export const Youtube = Node.create<YoutubeOptions>({
27
+ name: 'youtube',
28
+
29
+ addOptions() {
30
+ return {
31
+ inline: false,
32
+ controls: true,
33
+ HTMLAttributes: {},
34
+ nocookie: false,
35
+ allowFullscreen: false,
36
+ width: 640,
37
+ height: 480,
38
+ }
39
+ },
40
+
41
+ inline() {
42
+ return this.options.inline
43
+ },
44
+
45
+ group() {
46
+ return this.options.inline ? 'inline' : 'block'
47
+ },
48
+
49
+ draggable: true,
50
+
51
+ addAttributes() {
52
+ return {
53
+ src: {
54
+ default: null,
55
+ },
56
+ start: {
57
+ default: 0,
58
+ },
59
+ width: {
60
+ default: this.options.width,
61
+ },
62
+ height: {
63
+ default: this.options.height,
64
+ },
65
+ }
66
+ },
67
+
68
+ parseHTML() {
69
+ return [
70
+ {
71
+ tag: 'div[data-youtube-video] iframe',
72
+ },
73
+ ]
74
+ },
75
+
76
+ addCommands() {
77
+ return {
78
+ setYoutubeVideo: options => ({ commands }) => {
79
+ if (!isValidYoutubeUrl(options.src)) {
80
+ return false
81
+ }
82
+
83
+ return commands.insertContent({
84
+ type: this.name,
85
+ attrs: options,
86
+ })
87
+ },
88
+ }
89
+ },
90
+
91
+ renderHTML({ HTMLAttributes }) {
92
+ const embedUrl = getEmbedURLFromYoutubeURL({
93
+ url: HTMLAttributes.src,
94
+ controls: this.options.controls,
95
+ nocookie: this.options.nocookie,
96
+ startAt: HTMLAttributes.start || 0,
97
+ })
98
+
99
+ HTMLAttributes.src = embedUrl
100
+
101
+ return [
102
+ 'div',
103
+ { 'data-youtube-video': '' },
104
+ [
105
+ 'iframe',
106
+ mergeAttributes(
107
+ this.options.HTMLAttributes,
108
+ {
109
+ width: this.options.width,
110
+ height: this.options.height,
111
+ allowfullscreen: this.options.allowFullscreen,
112
+ },
113
+ HTMLAttributes,
114
+ ),
115
+ ],
116
+ ]
117
+ },
118
+ })