payload-richtext-tiptap 0.0.157 → 0.0.159
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/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/BlockquoteFigure.d.ts +1 -1
- package/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/BlockquoteFigure.d.ts.map +1 -1
- package/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/BlockquoteFigure.js +61 -15
- package/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/BlockquoteFigure.js.map +1 -1
- package/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/Quote/Quote.d.ts.map +1 -1
- package/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/Quote/Quote.js +1 -3
- package/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/Quote/Quote.js.map +1 -1
- package/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.js.map +1 -1
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/GifPlayer.d.ts +12 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/GifPlayer.d.ts.map +1 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/GifPlayer.js +152 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/GifPlayer.js.map +1 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/SmartImage.d.ts +12 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/SmartImage.d.ts.map +1 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/SmartImage.js +55 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/SmartImage.js.map +1 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/TestImage.d.ts +4 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/TestImage.d.ts.map +1 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/TestImage.js +26 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/components/TestImage.js.map +1 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/utils/gifUtils.d.ts +31 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/utils/gifUtils.d.ts.map +1 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/utils/gifUtils.js +62 -0
- package/dist/src/fields/TiptapEditor/extensions/ImageBlock/utils/gifUtils.js.map +1 -0
- package/dist/src/fields/TiptapEditor/features/menus/TextMenu/TextMenu.d.ts +2 -2
- package/dist/src/fields/TiptapEditor/features/menus/TextMenu/TextMenu.d.ts.map +1 -1
- package/dist/src/fields/TiptapEditor/features/menus/TextMenu/TextMenu.js +63 -58
- package/dist/src/fields/TiptapEditor/features/menus/TextMenu/TextMenu.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlockquoteFigure.d.ts","sourceRoot":"","sources":["../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/BlockquoteFigure.ts"],"names":[],"mappings":"AAKA,OAAO,QAAQ,cAAc,CAAC;IAE5B,UAAU,QAAQ,CAAC,UAAU;QAC3B,gBAAgB,EAAE;YAChB,aAAa,EAAE,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"BlockquoteFigure.d.ts","sourceRoot":"","sources":["../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/BlockquoteFigure.ts"],"names":[],"mappings":"AAKA,OAAO,QAAQ,cAAc,CAAC;IAE5B,UAAU,QAAQ,CAAC,UAAU;QAC3B,gBAAgB,EAAE;YAChB,aAAa,EAAE,MAAM,UAAU,CAAA;SAChC,CAAA;KACF;CACF;AAED,eAAO,MAAM,gBAAgB,uCA4H3B,CAAA;AAEF,eAAe,gBAAgB,CAAA"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { mergeAttributes } from
|
|
2
|
-
import { Figure } from
|
|
3
|
-
import { Quote } from
|
|
4
|
-
import { QuoteCaption } from
|
|
1
|
+
import { mergeAttributes } from '@tiptap/core';
|
|
2
|
+
import { Figure } from '../Figure/Figure.js';
|
|
3
|
+
import { Quote } from './Quote/Quote.js';
|
|
4
|
+
import { QuoteCaption } from './QuoteCaption/QuoteCaption.js';
|
|
5
5
|
export const BlockquoteFigure = Figure.extend({
|
|
6
|
-
name:
|
|
7
|
-
group:
|
|
8
|
-
content:
|
|
6
|
+
name: 'blockquoteFigure',
|
|
7
|
+
group: 'block',
|
|
8
|
+
content: 'quote quoteCaption',
|
|
9
9
|
isolating: true,
|
|
10
10
|
addExtensions () {
|
|
11
11
|
return [
|
|
@@ -15,12 +15,12 @@ export const BlockquoteFigure = Figure.extend({
|
|
|
15
15
|
},
|
|
16
16
|
renderHTML ({ HTMLAttributes }) {
|
|
17
17
|
return [
|
|
18
|
-
|
|
18
|
+
'figure',
|
|
19
19
|
mergeAttributes(HTMLAttributes, {
|
|
20
|
-
|
|
20
|
+
'data-type': this.name
|
|
21
21
|
}),
|
|
22
22
|
[
|
|
23
|
-
|
|
23
|
+
'div',
|
|
24
24
|
{},
|
|
25
25
|
0
|
|
26
26
|
]
|
|
@@ -28,7 +28,53 @@ export const BlockquoteFigure = Figure.extend({
|
|
|
28
28
|
},
|
|
29
29
|
addKeyboardShortcuts () {
|
|
30
30
|
return {
|
|
31
|
-
Enter: ()=>false
|
|
31
|
+
Enter: ()=>false,
|
|
32
|
+
Backspace: ({ editor })=>{
|
|
33
|
+
const { state } = editor;
|
|
34
|
+
const { selection } = state;
|
|
35
|
+
const { $from } = selection;
|
|
36
|
+
let blockquoteFigureNode = null;
|
|
37
|
+
let blockquoteFigureDepth = -1;
|
|
38
|
+
// Look deeper in the hierarchy - the BlockquoteFigure might be at a higher level
|
|
39
|
+
for(let i = $from.depth; i >= 0; i--){
|
|
40
|
+
const node = $from.node(i);
|
|
41
|
+
if (node.type.name === 'blockquoteFigure') {
|
|
42
|
+
blockquoteFigureNode = node;
|
|
43
|
+
blockquoteFigureDepth = i;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!blockquoteFigureNode) {
|
|
48
|
+
// Also check parent nodes that might not be in the depth range
|
|
49
|
+
let pos = $from.pos;
|
|
50
|
+
while(pos > 0){
|
|
51
|
+
const node = editor.state.doc.nodeAt(pos);
|
|
52
|
+
if (node && node.type.name === 'blockquoteFigure') {
|
|
53
|
+
blockquoteFigureNode = node;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
pos = editor.state.doc.resolve(pos).before();
|
|
57
|
+
if (pos === 0) break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!blockquoteFigureNode) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
// Check if we're at the start of the current node
|
|
64
|
+
const isAtStart = $from.parentOffset === 0;
|
|
65
|
+
// Find the quote and caption nodes within the BlockquoteFigure
|
|
66
|
+
const quoteNode = blockquoteFigureNode.firstChild;
|
|
67
|
+
const captionNode = blockquoteFigureNode.lastChild;
|
|
68
|
+
// Check if both quote and caption are empty
|
|
69
|
+
const isQuoteEmpty = quoteNode && (quoteNode.content.size === 0 || quoteNode.content.size === 2 && quoteNode.firstChild?.type.name === 'paragraph' && quoteNode.firstChild.content.size === 0);
|
|
70
|
+
const isCaptionEmpty = captionNode && captionNode.content.size === 0;
|
|
71
|
+
// Delete if we're at the start and both quote and caption are empty
|
|
72
|
+
if (isAtStart && isQuoteEmpty && isCaptionEmpty) {
|
|
73
|
+
const pos = $from.before(blockquoteFigureDepth);
|
|
74
|
+
return editor.chain().setNodeSelection(pos).deleteSelection().run();
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
32
78
|
};
|
|
33
79
|
},
|
|
34
80
|
addAttributes () {
|
|
@@ -45,18 +91,18 @@ export const BlockquoteFigure = Figure.extend({
|
|
|
45
91
|
type: this.name,
|
|
46
92
|
content: [
|
|
47
93
|
{
|
|
48
|
-
type:
|
|
94
|
+
type: 'quote',
|
|
49
95
|
content: selectionContent.content.toJSON() || [
|
|
50
96
|
{
|
|
51
|
-
type:
|
|
97
|
+
type: 'paragraph',
|
|
52
98
|
attrs: {
|
|
53
|
-
textAlign:
|
|
99
|
+
textAlign: 'left'
|
|
54
100
|
}
|
|
55
101
|
}
|
|
56
102
|
]
|
|
57
103
|
},
|
|
58
104
|
{
|
|
59
|
-
type:
|
|
105
|
+
type: 'quoteCaption'
|
|
60
106
|
}
|
|
61
107
|
]
|
|
62
108
|
}).focus(position + 1).run();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/BlockquoteFigure.ts"],"sourcesContent":["import { mergeAttributes } from
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/BlockquoteFigure.ts"],"sourcesContent":["import { mergeAttributes } from '@tiptap/core'\nimport { Figure } from '../Figure/Figure.js'\nimport { Quote } from './Quote/Quote.js'\nimport { QuoteCaption } from './QuoteCaption/QuoteCaption.js'\n\ndeclare module '@tiptap/core' {\n // eslint-disable-next-line no-unused-vars\n interface Commands<ReturnType> {\n blockquoteFigure: {\n setBlockquote: () => ReturnType\n }\n }\n}\n\nexport const BlockquoteFigure = Figure.extend({\n name: 'blockquoteFigure',\n\n group: 'block',\n\n content: 'quote quoteCaption',\n\n isolating: true,\n\n addExtensions() {\n return [Quote, QuoteCaption]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['figure', mergeAttributes(HTMLAttributes, { 'data-type': this.name }), ['div', {}, 0]]\n },\n\n addKeyboardShortcuts() {\n return {\n Enter: () => false,\n Backspace: ({ editor }) => {\n const { state } = editor\n const { selection } = state\n const { $from } = selection\n\n let blockquoteFigureNode = null\n let blockquoteFigureDepth = -1\n\n // Look deeper in the hierarchy - the BlockquoteFigure might be at a higher level\n for (let i = $from.depth; i >= 0; i--) {\n const node = $from.node(i)\n if (node.type.name === 'blockquoteFigure') {\n blockquoteFigureNode = node\n blockquoteFigureDepth = i\n break\n }\n }\n\n if (!blockquoteFigureNode) {\n // Also check parent nodes that might not be in the depth range\n let pos = $from.pos\n while (pos > 0) {\n const node = editor.state.doc.nodeAt(pos)\n if (node && node.type.name === 'blockquoteFigure') {\n blockquoteFigureNode = node\n break\n }\n pos = editor.state.doc.resolve(pos).before()\n if (pos === 0) break\n }\n }\n\n if (!blockquoteFigureNode) {\n return false\n }\n\n // Check if we're at the start of the current node\n const isAtStart = $from.parentOffset === 0\n\n // Find the quote and caption nodes within the BlockquoteFigure\n const quoteNode = blockquoteFigureNode.firstChild\n const captionNode = blockquoteFigureNode.lastChild\n\n // Check if both quote and caption are empty\n const isQuoteEmpty =\n quoteNode &&\n (quoteNode.content.size === 0 ||\n (quoteNode.content.size === 2 &&\n quoteNode.firstChild?.type.name === 'paragraph' &&\n quoteNode.firstChild.content.size === 0))\n\n const isCaptionEmpty = captionNode && captionNode.content.size === 0\n\n // Delete if we're at the start and both quote and caption are empty\n if (isAtStart && isQuoteEmpty && isCaptionEmpty) {\n const pos = $from.before(blockquoteFigureDepth)\n return editor.chain().setNodeSelection(pos).deleteSelection().run()\n }\n\n return false\n },\n }\n },\n\n addAttributes() {\n return {\n ...this.parent?.(),\n }\n },\n\n addCommands() {\n return {\n setBlockquote:\n () =>\n ({ state, chain }) => {\n const position = state.selection.$from.start()\n const selectionContent = state.selection.content()\n\n return chain()\n .focus()\n .insertContent({\n type: this.name,\n content: [\n {\n type: 'quote',\n content: selectionContent.content.toJSON() || [\n {\n type: 'paragraph',\n attrs: {\n textAlign: 'left',\n },\n },\n ],\n },\n {\n type: 'quoteCaption',\n },\n ],\n })\n .focus(position + 1)\n .run()\n },\n }\n },\n})\n\nexport default BlockquoteFigure\n"],"names":["mergeAttributes","Figure","Quote","QuoteCaption","BlockquoteFigure","extend","name","group","content","isolating","addExtensions","renderHTML","HTMLAttributes","addKeyboardShortcuts","Enter","Backspace","editor","state","selection","$from","blockquoteFigureNode","blockquoteFigureDepth","i","depth","node","type","pos","doc","nodeAt","resolve","before","isAtStart","parentOffset","quoteNode","firstChild","captionNode","lastChild","isQuoteEmpty","size","isCaptionEmpty","chain","setNodeSelection","deleteSelection","run","addAttributes","parent","addCommands","setBlockquote","position","start","selectionContent","focus","insertContent","toJSON","attrs","textAlign"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Quote.d.ts","sourceRoot":"","sources":["../../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/Quote/Quote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAEnC,eAAO,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"Quote.d.ts","sourceRoot":"","sources":["../../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/Quote/Quote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAEnC,eAAO,MAAM,KAAK,gBAwBhB,CAAA;AAEF,eAAe,KAAK,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/Quote/Quote.ts"],"sourcesContent":["import { Node } from '@tiptap/core'\
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/Quote/Quote.ts"],"sourcesContent":["import { Node } from '@tiptap/core'\n\nexport const Quote = Node.create({\n name: 'quote',\n\n content: 'paragraph+',\n\n defining: true,\n\n marks: '',\n\n parseHTML() {\n return [\n {\n tag: 'blockquote',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['blockquote', HTMLAttributes, 0]\n },\n\n addKeyboardShortcuts() {\n return {}\n },\n})\n\nexport default Quote\n"],"names":["Node","Quote","create","name","content","defining","marks","parseHTML","tag","renderHTML","HTMLAttributes","addKeyboardShortcuts"],"mappings":"AAAA,SAASA,IAAI,QAAQ,eAAc;AAEnC,OAAO,MAAMC,QAAQD,KAAKE,MAAM,CAAC;IAC/BC,MAAM;IAENC,SAAS;IAETC,UAAU;IAEVC,OAAO;IAEPC;QACE,OAAO;YACL;gBACEC,KAAK;YACP;SACD;IACH;IAEAC,YAAW,EAAEC,cAAc,EAAE;QAC3B,OAAO;YAAC;YAAcA;YAAgB;SAAE;IAC1C;IAEAC;QACE,OAAO,CAAC;IACV;AACF,GAAE;AAEF,eAAeV,MAAK"}
|
package/dist/src/fields/TiptapEditor/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.ts"],"sourcesContent":["import { Node } from '@tiptap/core'\
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/fields/TiptapEditor/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.ts"],"sourcesContent":["import { Node } from '@tiptap/core'\n\nexport const QuoteCaption = Node.create({\n name: 'quoteCaption',\n\n group: 'block',\n\n content: 'text*',\n\n defining: true,\n\n isolating: true,\n\n parseHTML() {\n return [\n {\n tag: 'figcaption',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['figcaption', HTMLAttributes, 0]\n },\n\n addKeyboardShortcuts() {\n return {\n // On Enter at the end of line, create new paragraph and focus\n Enter: ({ editor }) => {\n const {\n state: {\n selection: { $from, empty },\n },\n } = editor\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n\n if (!isAtEnd) {\n return false\n }\n\n const pos = editor.state.selection.$from.end()\n\n return editor.chain().focus(pos).insertContentAt(pos, { type: 'paragraph' }).run()\n },\n }\n },\n})\n\nexport default QuoteCaption\n"],"names":["Node","QuoteCaption","create","name","group","content","defining","isolating","parseHTML","tag","renderHTML","HTMLAttributes","addKeyboardShortcuts","Enter","editor","state","selection","$from","empty","parent","type","isAtEnd","parentOffset","nodeSize","pos","end","chain","focus","insertContentAt","run"],"mappings":"AAAA,SAASA,IAAI,QAAQ,eAAc;AAEnC,OAAO,MAAMC,eAAeD,KAAKE,MAAM,CAAC;IACtCC,MAAM;IAENC,OAAO;IAEPC,SAAS;IAETC,UAAU;IAEVC,WAAW;IAEXC;QACE,OAAO;YACL;gBACEC,KAAK;YACP;SACD;IACH;IAEAC,YAAW,EAAEC,cAAc,EAAE;QAC3B,OAAO;YAAC;YAAcA;YAAgB;SAAE;IAC1C;IAEAC;QACE,OAAO;YACL,8DAA8D;YAC9DC,OAAO,CAAC,EAAEC,MAAM,EAAE;gBAChB,MAAM,EACJC,OAAO,EACLC,WAAW,EAAEC,KAAK,EAAEC,KAAK,EAAE,EAC5B,EACF,GAAGJ;gBAEJ,IAAI,CAACI,SAASD,MAAME,MAAM,CAACC,IAAI,KAAK,IAAI,CAACA,IAAI,EAAE;oBAC7C,OAAO;gBACT;gBAEA,MAAMC,UAAUJ,MAAMK,YAAY,KAAKL,MAAME,MAAM,CAACI,QAAQ,GAAG;gBAE/D,IAAI,CAACF,SAAS;oBACZ,OAAO;gBACT;gBAEA,MAAMG,MAAMV,OAAOC,KAAK,CAACC,SAAS,CAACC,KAAK,CAACQ,GAAG;gBAE5C,OAAOX,OAAOY,KAAK,GAAGC,KAAK,CAACH,KAAKI,eAAe,CAACJ,KAAK;oBAAEJ,MAAM;gBAAY,GAAGS,GAAG;YAClF;QACF;IACF;AACF,GAAE;AAEF,eAAe5B,aAAY"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface GifPlayerProps {
|
|
3
|
+
src: string;
|
|
4
|
+
alt?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
onClick?: () => void;
|
|
7
|
+
width?: number;
|
|
8
|
+
height?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const GifPlayer: React.FC<GifPlayerProps>;
|
|
11
|
+
export default GifPlayer;
|
|
12
|
+
//# sourceMappingURL=GifPlayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GifPlayer.d.ts","sourceRoot":"","sources":["../../../../../../../src/fields/TiptapEditor/extensions/ImageBlock/components/GifPlayer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAA;AAG1D,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAmL9C,CAAA;AAED,eAAe,SAAS,CAAA"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { decompressFrames, parseGIF } from 'gifuct-js';
|
|
4
|
+
export const GifPlayer = ({ src, alt = '', className = '', onClick, width, height })=>{
|
|
5
|
+
const canvasRef = useRef(null);
|
|
6
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
7
|
+
const [error, setError] = useState(null);
|
|
8
|
+
const animationRef = useRef(undefined);
|
|
9
|
+
const framesRef = useRef([]);
|
|
10
|
+
const currentFrameRef = useRef(0);
|
|
11
|
+
const startTimeRef = useRef(0);
|
|
12
|
+
useEffect(()=>{
|
|
13
|
+
let isMounted = true;
|
|
14
|
+
const loadGif = async ()=>{
|
|
15
|
+
try {
|
|
16
|
+
setIsLoading(true);
|
|
17
|
+
setError(null);
|
|
18
|
+
console.log('GifPlayer: Loading GIF from:', src);
|
|
19
|
+
// Fetch the GIF data
|
|
20
|
+
const response = await fetch(src);
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Failed to fetch GIF: ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
25
|
+
console.log('GifPlayer: GIF loaded, size:', arrayBuffer.byteLength);
|
|
26
|
+
// Parse and decompress the GIF
|
|
27
|
+
const gif = parseGIF(arrayBuffer);
|
|
28
|
+
const frames = decompressFrames(gif, true);
|
|
29
|
+
console.log('GifPlayer: GIF parsed, frames:', frames.length);
|
|
30
|
+
if (!isMounted) return;
|
|
31
|
+
framesRef.current = frames;
|
|
32
|
+
setIsLoading(false);
|
|
33
|
+
// Set canvas dimensions
|
|
34
|
+
const canvas = canvasRef.current;
|
|
35
|
+
if (canvas && frames.length > 0) {
|
|
36
|
+
const firstFrame = frames[0];
|
|
37
|
+
canvas.width = width || firstFrame.dims.width;
|
|
38
|
+
canvas.height = height || firstFrame.dims.height;
|
|
39
|
+
console.log('GifPlayer: Canvas dimensions set:', canvas.width, 'x', canvas.height);
|
|
40
|
+
}
|
|
41
|
+
// Start animation
|
|
42
|
+
startAnimation();
|
|
43
|
+
} catch (err) {
|
|
44
|
+
console.error('GifPlayer: Error loading GIF:', err);
|
|
45
|
+
if (isMounted) {
|
|
46
|
+
setError(err instanceof Error ? err.message : 'Failed to load GIF');
|
|
47
|
+
setIsLoading(false);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const startAnimation = ()=>{
|
|
52
|
+
const canvas = canvasRef.current;
|
|
53
|
+
if (!canvas || framesRef.current.length === 0) return;
|
|
54
|
+
const ctx = canvas.getContext('2d');
|
|
55
|
+
if (!ctx) return;
|
|
56
|
+
startTimeRef.current = performance.now();
|
|
57
|
+
const animate = (currentTime)=>{
|
|
58
|
+
if (!isMounted) return;
|
|
59
|
+
const frames = framesRef.current;
|
|
60
|
+
if (frames.length === 0) return;
|
|
61
|
+
// Calculate which frame to show based on elapsed time
|
|
62
|
+
let elapsed = currentTime - startTimeRef.current;
|
|
63
|
+
let frameIndex = 0;
|
|
64
|
+
let frameTime = 0;
|
|
65
|
+
// Find the current frame based on timing
|
|
66
|
+
for(let i = 0; i < frames.length; i++){
|
|
67
|
+
const frame = frames[i];
|
|
68
|
+
const delay = frame.delay || 100 // Default 100ms if no delay specified
|
|
69
|
+
;
|
|
70
|
+
if (elapsed < frameTime + delay) {
|
|
71
|
+
frameIndex = i;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
frameTime += delay;
|
|
75
|
+
}
|
|
76
|
+
// If we've gone through all frames, restart the loop (infinite loop)
|
|
77
|
+
if (elapsed >= frameTime) {
|
|
78
|
+
startTimeRef.current = currentTime;
|
|
79
|
+
frameIndex = 0;
|
|
80
|
+
elapsed = 0;
|
|
81
|
+
}
|
|
82
|
+
// Only update if frame changed
|
|
83
|
+
if (frameIndex !== currentFrameRef.current) {
|
|
84
|
+
currentFrameRef.current = frameIndex;
|
|
85
|
+
const frame = frames[frameIndex];
|
|
86
|
+
// Clear canvas
|
|
87
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
88
|
+
// Draw the frame
|
|
89
|
+
if (frame.patch) {
|
|
90
|
+
try {
|
|
91
|
+
const imageData = new ImageData(frame.patch, frame.dims.width, frame.dims.height);
|
|
92
|
+
ctx.putImageData(imageData, frame.dims.left, frame.dims.top);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.error('Error drawing frame:', err);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
99
|
+
};
|
|
100
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
101
|
+
};
|
|
102
|
+
loadGif();
|
|
103
|
+
return ()=>{
|
|
104
|
+
isMounted = false;
|
|
105
|
+
if (animationRef.current) {
|
|
106
|
+
cancelAnimationFrame(animationRef.current);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}, [
|
|
110
|
+
src,
|
|
111
|
+
width,
|
|
112
|
+
height
|
|
113
|
+
]);
|
|
114
|
+
if (error) {
|
|
115
|
+
// Fallback to regular img tag if GIF parsing fails
|
|
116
|
+
return /*#__PURE__*/ _jsx("img", {
|
|
117
|
+
className: className,
|
|
118
|
+
src: src,
|
|
119
|
+
alt: alt,
|
|
120
|
+
onClick: onClick,
|
|
121
|
+
style: {
|
|
122
|
+
width: width ? `${width}px` : '100%',
|
|
123
|
+
height: height ? `${height}px` : 'auto',
|
|
124
|
+
maxWidth: '100%',
|
|
125
|
+
display: 'block'
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (isLoading) {
|
|
130
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
131
|
+
className: `flex items-center justify-center bg-gray-100 ${className}`,
|
|
132
|
+
children: /*#__PURE__*/ _jsx("span", {
|
|
133
|
+
className: "text-gray-500 text-sm",
|
|
134
|
+
children: "Loading GIF..."
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return /*#__PURE__*/ _jsx("canvas", {
|
|
139
|
+
ref: canvasRef,
|
|
140
|
+
className: className,
|
|
141
|
+
onClick: onClick,
|
|
142
|
+
style: {
|
|
143
|
+
width: width ? `${width}px` : '100%',
|
|
144
|
+
height: height ? `${height}px` : 'auto',
|
|
145
|
+
maxWidth: '100%',
|
|
146
|
+
display: 'block'
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
export default GifPlayer;
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=GifPlayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/fields/TiptapEditor/extensions/ImageBlock/components/GifPlayer.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react'\r\nimport { decompressFrames, parseGIF } from 'gifuct-js'\r\n\r\ninterface GifPlayerProps {\r\n src: string\r\n alt?: string\r\n className?: string\r\n onClick?: () => void\r\n width?: number\r\n height?: number\r\n}\r\n\r\nexport const GifPlayer: React.FC<GifPlayerProps> = ({\r\n src,\r\n alt = '',\r\n className = '',\r\n onClick,\r\n width,\r\n height,\r\n}) => {\r\n const canvasRef = useRef<HTMLCanvasElement>(null)\r\n const [isLoading, setIsLoading] = useState(true)\r\n const [error, setError] = useState<string | null>(null)\r\n const animationRef = useRef<number | undefined>(undefined)\r\n const framesRef = useRef<any[]>([])\r\n const currentFrameRef = useRef(0)\r\n const startTimeRef = useRef(0)\r\n\r\n useEffect(() => {\r\n let isMounted = true\r\n\r\n const loadGif = async () => {\r\n try {\r\n setIsLoading(true)\r\n setError(null)\r\n\r\n console.log('GifPlayer: Loading GIF from:', src)\r\n\r\n // Fetch the GIF data\r\n const response = await fetch(src)\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch GIF: ${response.statusText}`)\r\n }\r\n\r\n const arrayBuffer = await response.arrayBuffer()\r\n console.log('GifPlayer: GIF loaded, size:', arrayBuffer.byteLength)\r\n\r\n // Parse and decompress the GIF\r\n const gif = parseGIF(arrayBuffer)\r\n const frames = decompressFrames(gif, true)\r\n\r\n console.log('GifPlayer: GIF parsed, frames:', frames.length)\r\n\r\n if (!isMounted) return\r\n\r\n framesRef.current = frames\r\n setIsLoading(false)\r\n\r\n // Set canvas dimensions\r\n const canvas = canvasRef.current\r\n if (canvas && frames.length > 0) {\r\n const firstFrame = frames[0]\r\n canvas.width = width || firstFrame.dims.width\r\n canvas.height = height || firstFrame.dims.height\r\n console.log('GifPlayer: Canvas dimensions set:', canvas.width, 'x', canvas.height)\r\n }\r\n\r\n // Start animation\r\n startAnimation()\r\n } catch (err) {\r\n console.error('GifPlayer: Error loading GIF:', err)\r\n if (isMounted) {\r\n setError(err instanceof Error ? err.message : 'Failed to load GIF')\r\n setIsLoading(false)\r\n }\r\n }\r\n }\r\n\r\n const startAnimation = () => {\r\n const canvas = canvasRef.current\r\n if (!canvas || framesRef.current.length === 0) return\r\n\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) return\r\n\r\n startTimeRef.current = performance.now()\r\n\r\n const animate = (currentTime: number) => {\r\n if (!isMounted) return\r\n\r\n const frames = framesRef.current\r\n if (frames.length === 0) return\r\n\r\n // Calculate which frame to show based on elapsed time\r\n let elapsed = currentTime - startTimeRef.current\r\n let frameIndex = 0\r\n let frameTime = 0\r\n\r\n // Find the current frame based on timing\r\n for (let i = 0; i < frames.length; i++) {\r\n const frame = frames[i]\r\n const delay = frame.delay || 100 // Default 100ms if no delay specified\r\n\r\n if (elapsed < frameTime + delay) {\r\n frameIndex = i\r\n break\r\n }\r\n frameTime += delay\r\n }\r\n\r\n // If we've gone through all frames, restart the loop (infinite loop)\r\n if (elapsed >= frameTime) {\r\n startTimeRef.current = currentTime\r\n frameIndex = 0\r\n elapsed = 0\r\n }\r\n\r\n // Only update if frame changed\r\n if (frameIndex !== currentFrameRef.current) {\r\n currentFrameRef.current = frameIndex\r\n const frame = frames[frameIndex]\r\n\r\n // Clear canvas\r\n ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Draw the frame\r\n if (frame.patch) {\r\n try {\r\n const imageData = new ImageData(frame.patch, frame.dims.width, frame.dims.height)\r\n ctx.putImageData(imageData, frame.dims.left, frame.dims.top)\r\n } catch (err) {\r\n console.error('Error drawing frame:', err)\r\n }\r\n }\r\n }\r\n\r\n animationRef.current = requestAnimationFrame(animate)\r\n }\r\n\r\n animationRef.current = requestAnimationFrame(animate)\r\n }\r\n\r\n loadGif()\r\n\r\n return () => {\r\n isMounted = false\r\n if (animationRef.current) {\r\n cancelAnimationFrame(animationRef.current)\r\n }\r\n }\r\n }, [src, width, height])\r\n\r\n if (error) {\r\n // Fallback to regular img tag if GIF parsing fails\r\n return (\r\n <img\r\n className={className}\r\n src={src}\r\n alt={alt}\r\n onClick={onClick}\r\n style={{\r\n width: width ? `${width}px` : '100%',\r\n height: height ? `${height}px` : 'auto',\r\n maxWidth: '100%',\r\n display: 'block',\r\n }}\r\n />\r\n )\r\n }\r\n\r\n if (isLoading) {\r\n return (\r\n <div className={`flex items-center justify-center bg-gray-100 ${className}`}>\r\n <span className='text-gray-500 text-sm'>Loading GIF...</span>\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <canvas\r\n ref={canvasRef}\r\n className={className}\r\n onClick={onClick}\r\n style={{\r\n width: width ? `${width}px` : '100%',\r\n height: height ? `${height}px` : 'auto',\r\n maxWidth: '100%',\r\n display: 'block',\r\n }}\r\n />\r\n )\r\n}\r\n\r\nexport default GifPlayer\r\n"],"names":["React","useEffect","useRef","useState","decompressFrames","parseGIF","GifPlayer","src","alt","className","onClick","width","height","canvasRef","isLoading","setIsLoading","error","setError","animationRef","undefined","framesRef","currentFrameRef","startTimeRef","isMounted","loadGif","console","log","response","fetch","ok","Error","statusText","arrayBuffer","byteLength","gif","frames","length","current","canvas","firstFrame","dims","startAnimation","err","message","ctx","getContext","performance","now","animate","currentTime","elapsed","frameIndex","frameTime","i","frame","delay","clearRect","patch","imageData","ImageData","putImageData","left","top","requestAnimationFrame","cancelAnimationFrame","img","style","maxWidth","display","div","span","ref"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface SmartImageProps {
|
|
3
|
+
src: string;
|
|
4
|
+
alt?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
onClick?: () => void;
|
|
7
|
+
width?: number;
|
|
8
|
+
height?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const SmartImage: React.FC<SmartImageProps>;
|
|
11
|
+
export default SmartImage;
|
|
12
|
+
//# sourceMappingURL=SmartImage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmartImage.d.ts","sourceRoot":"","sources":["../../../../../../../src/fields/TiptapEditor/extensions/ImageBlock/components/SmartImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAIvC,UAAU,eAAe;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA2DhD,CAAA;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { GifPlayer } from './GifPlayer.js';
|
|
4
|
+
import { shouldRenderAsGif } from '../utils/gifUtils.js';
|
|
5
|
+
export const SmartImage = ({ src, alt = '', className = '', onClick, width, height })=>{
|
|
6
|
+
const [gifPlayerFailed, setGifPlayerFailed] = useState(false);
|
|
7
|
+
const isGif = shouldRenderAsGif(src);
|
|
8
|
+
// If it's not a GIF or GIF player failed, use regular img
|
|
9
|
+
if (!isGif || gifPlayerFailed) {
|
|
10
|
+
return /*#__PURE__*/ _jsx("img", {
|
|
11
|
+
className: className,
|
|
12
|
+
src: src,
|
|
13
|
+
alt: alt,
|
|
14
|
+
onClick: onClick,
|
|
15
|
+
style: {
|
|
16
|
+
width: width ? `${width}px` : '100%',
|
|
17
|
+
height: height ? `${height}px` : 'auto',
|
|
18
|
+
maxWidth: '100%',
|
|
19
|
+
display: 'block'
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
// Try GIF player, with fallback to img if it fails
|
|
24
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
25
|
+
children: [
|
|
26
|
+
/*#__PURE__*/ _jsx(GifPlayer, {
|
|
27
|
+
src: src,
|
|
28
|
+
alt: alt,
|
|
29
|
+
className: className,
|
|
30
|
+
onClick: onClick,
|
|
31
|
+
width: width,
|
|
32
|
+
height: height
|
|
33
|
+
}),
|
|
34
|
+
/*#__PURE__*/ _jsx("img", {
|
|
35
|
+
className: className,
|
|
36
|
+
src: src,
|
|
37
|
+
alt: alt,
|
|
38
|
+
onClick: onClick,
|
|
39
|
+
style: {
|
|
40
|
+
width: width ? `${width}px` : '100%',
|
|
41
|
+
height: height ? `${height}px` : 'auto',
|
|
42
|
+
maxWidth: '100%',
|
|
43
|
+
display: 'none'
|
|
44
|
+
},
|
|
45
|
+
onError: ()=>{
|
|
46
|
+
console.log('GIF player failed, falling back to img');
|
|
47
|
+
setGifPlayerFailed(true);
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
export default SmartImage;
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=SmartImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/fields/TiptapEditor/extensions/ImageBlock/components/SmartImage.tsx"],"sourcesContent":["import React, { useState } from 'react'\r\nimport { GifPlayer } from './GifPlayer.js'\r\nimport { shouldRenderAsGif } from '../utils/gifUtils.js'\r\n\r\ninterface SmartImageProps {\r\n src: string\r\n alt?: string\r\n className?: string\r\n onClick?: () => void\r\n width?: number\r\n height?: number\r\n}\r\n\r\nexport const SmartImage: React.FC<SmartImageProps> = ({\r\n src,\r\n alt = '',\r\n className = '',\r\n onClick,\r\n width,\r\n height,\r\n}) => {\r\n const [gifPlayerFailed, setGifPlayerFailed] = useState(false)\r\n const isGif = shouldRenderAsGif(src)\r\n\r\n // If it's not a GIF or GIF player failed, use regular img\r\n if (!isGif || gifPlayerFailed) {\r\n return (\r\n <img\r\n className={className}\r\n src={src}\r\n alt={alt}\r\n onClick={onClick}\r\n style={{\r\n width: width ? `${width}px` : '100%',\r\n height: height ? `${height}px` : 'auto',\r\n maxWidth: '100%',\r\n display: 'block',\r\n }}\r\n />\r\n )\r\n }\r\n\r\n // Try GIF player, with fallback to img if it fails\r\n return (\r\n <div>\r\n <GifPlayer\r\n src={src}\r\n alt={alt}\r\n className={className}\r\n onClick={onClick}\r\n width={width}\r\n height={height}\r\n />\r\n {/* Hidden fallback img that will show if GIF player fails */}\r\n <img\r\n className={className}\r\n src={src}\r\n alt={alt}\r\n onClick={onClick}\r\n style={{\r\n width: width ? `${width}px` : '100%',\r\n height: height ? `${height}px` : 'auto',\r\n maxWidth: '100%',\r\n display: 'none', // Hidden by default\r\n }}\r\n onError={() => {\r\n console.log('GIF player failed, falling back to img')\r\n setGifPlayerFailed(true)\r\n }}\r\n />\r\n </div>\r\n )\r\n}\r\n\r\nexport default SmartImage\r\n"],"names":["React","useState","GifPlayer","shouldRenderAsGif","SmartImage","src","alt","className","onClick","width","height","gifPlayerFailed","setGifPlayerFailed","isGif","img","style","maxWidth","display","div","onError","console","log"],"mappings":";AAAA,OAAOA,SAASC,QAAQ,QAAQ,QAAO;AACvC,SAASC,SAAS,QAAQ,iBAAgB;AAC1C,SAASC,iBAAiB,QAAQ,uBAAsB;AAWxD,OAAO,MAAMC,aAAwC,CAAC,EACpDC,GAAG,EACHC,MAAM,EAAE,EACRC,YAAY,EAAE,EACdC,OAAO,EACPC,KAAK,EACLC,MAAM,EACP;IACC,MAAM,CAACC,iBAAiBC,mBAAmB,GAAGX,SAAS;IACvD,MAAMY,QAAQV,kBAAkBE;IAEhC,0DAA0D;IAC1D,IAAI,CAACQ,SAASF,iBAAiB;QAC7B,qBACE,KAACG;YACCP,WAAWA;YACXF,KAAKA;YACLC,KAAKA;YACLE,SAASA;YACTO,OAAO;gBACLN,OAAOA,QAAQ,GAAGA,MAAM,EAAE,CAAC,GAAG;gBAC9BC,QAAQA,SAAS,GAAGA,OAAO,EAAE,CAAC,GAAG;gBACjCM,UAAU;gBACVC,SAAS;YACX;;IAGN;IAEA,mDAAmD;IACnD,qBACE,MAACC;;0BACC,KAAChB;gBACCG,KAAKA;gBACLC,KAAKA;gBACLC,WAAWA;gBACXC,SAASA;gBACTC,OAAOA;gBACPC,QAAQA;;0BAGV,KAACI;gBACCP,WAAWA;gBACXF,KAAKA;gBACLC,KAAKA;gBACLE,SAASA;gBACTO,OAAO;oBACLN,OAAOA,QAAQ,GAAGA,MAAM,EAAE,CAAC,GAAG;oBAC9BC,QAAQA,SAAS,GAAGA,OAAO,EAAE,CAAC,GAAG;oBACjCM,UAAU;oBACVC,SAAS;gBACX;gBACAE,SAAS;oBACPC,QAAQC,GAAG,CAAC;oBACZT,mBAAmB;gBACrB;;;;AAIR,EAAC;AAED,eAAeR,WAAU"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestImage.d.ts","sourceRoot":"","sources":["../../../../../../../src/fields/TiptapEditor/extensions/ImageBlock/components/TestImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAY7B,CAAA;AAED,eAAe,SAAS,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export const TestImage = ()=>{
|
|
4
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
5
|
+
children: [
|
|
6
|
+
/*#__PURE__*/ _jsx("h3", {
|
|
7
|
+
children: "Test Image Component"
|
|
8
|
+
}),
|
|
9
|
+
/*#__PURE__*/ _jsx("img", {
|
|
10
|
+
src: "https://via.placeholder.com/300x200/0000FF/FFFFFF?text=Test+Image",
|
|
11
|
+
alt: "Test Image",
|
|
12
|
+
style: {
|
|
13
|
+
width: '300px',
|
|
14
|
+
height: '200px',
|
|
15
|
+
border: '1px solid #ccc'
|
|
16
|
+
}
|
|
17
|
+
}),
|
|
18
|
+
/*#__PURE__*/ _jsx("p", {
|
|
19
|
+
children: "If you can see this image, the basic image functionality is working."
|
|
20
|
+
})
|
|
21
|
+
]
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
export default TestImage;
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=TestImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/fields/TiptapEditor/extensions/ImageBlock/components/TestImage.tsx"],"sourcesContent":["import React from 'react'\r\n\r\nexport const TestImage: React.FC = () => {\r\n return (\r\n <div>\r\n <h3>Test Image Component</h3>\r\n <img\r\n src='https://via.placeholder.com/300x200/0000FF/FFFFFF?text=Test+Image'\r\n alt='Test Image'\r\n style={{ width: '300px', height: '200px', border: '1px solid #ccc' }}\r\n />\r\n <p>If you can see this image, the basic image functionality is working.</p>\r\n </div>\r\n )\r\n}\r\n\r\nexport default TestImage\r\n"],"names":["React","TestImage","div","h3","img","src","alt","style","width","height","border","p"],"mappings":";AAAA,OAAOA,WAAW,QAAO;AAEzB,OAAO,MAAMC,YAAsB;IACjC,qBACE,MAACC;;0BACC,KAACC;0BAAG;;0BACJ,KAACC;gBACCC,KAAI;gBACJC,KAAI;gBACJC,OAAO;oBAAEC,OAAO;oBAASC,QAAQ;oBAASC,QAAQ;gBAAiB;;0BAErE,KAACC;0BAAE;;;;AAGT,EAAC;AAED,eAAeV,UAAS"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for GIF handling
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Checks if a URL or file path points to a GIF file
|
|
6
|
+
* @param src - The source URL or file path
|
|
7
|
+
* @returns true if the source is a GIF file
|
|
8
|
+
*/
|
|
9
|
+
export declare const isGifFile: (src: string) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Checks if a URL is a data URL containing a GIF
|
|
12
|
+
* @param src - The source URL
|
|
13
|
+
* @returns true if the source is a data URL with GIF data
|
|
14
|
+
*/
|
|
15
|
+
export declare const isGifDataUrl: (src: string) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Determines if an image source should be rendered as a GIF
|
|
18
|
+
* @param src - The image source URL
|
|
19
|
+
* @returns true if the source should be rendered as a GIF
|
|
20
|
+
*/
|
|
21
|
+
export declare const shouldRenderAsGif: (src: string) => boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Extracts dimensions from a GIF source for proper canvas sizing
|
|
24
|
+
* @param src - The GIF source URL
|
|
25
|
+
* @returns Promise resolving to width and height, or null if extraction fails
|
|
26
|
+
*/
|
|
27
|
+
export declare const getGifDimensions: (src: string) => Promise<{
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
} | null>;
|
|
31
|
+
//# sourceMappingURL=gifUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gifUtils.d.ts","sourceRoot":"","sources":["../../../../../../../src/fields/TiptapEditor/extensions/ImageBlock/utils/gifUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAS,MAAM,KAAG,OAgBvC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAS,MAAM,KAAG,OAK1C,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAS,MAAM,KAAG,OAE/C,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QACtB,MAAM,KACV,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAoBlD,CAAA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for GIF handling
|
|
3
|
+
*/ /**
|
|
4
|
+
* Checks if a URL or file path points to a GIF file
|
|
5
|
+
* @param src - The source URL or file path
|
|
6
|
+
* @returns true if the source is a GIF file
|
|
7
|
+
*/ export const isGifFile = (src)=>{
|
|
8
|
+
if (!src) return false;
|
|
9
|
+
// Check file extension
|
|
10
|
+
const extension = src.toLowerCase().split('.').pop();
|
|
11
|
+
if (extension === 'gif') {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
// Check for GIF in URL path (even without extension)
|
|
15
|
+
const urlPath = src.toLowerCase();
|
|
16
|
+
if (urlPath.includes('.gif') || urlPath.includes('gif')) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Checks if a URL is a data URL containing a GIF
|
|
23
|
+
* @param src - The source URL
|
|
24
|
+
* @returns true if the source is a data URL with GIF data
|
|
25
|
+
*/ export const isGifDataUrl = (src)=>{
|
|
26
|
+
if (!src || !src.startsWith('data:')) return false;
|
|
27
|
+
// Check for GIF MIME type in data URL
|
|
28
|
+
return src.includes('data:image/gif') || src.includes('image/gif');
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Determines if an image source should be rendered as a GIF
|
|
32
|
+
* @param src - The image source URL
|
|
33
|
+
* @returns true if the source should be rendered as a GIF
|
|
34
|
+
*/ export const shouldRenderAsGif = (src)=>{
|
|
35
|
+
return isGifFile(src) || isGifDataUrl(src);
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Extracts dimensions from a GIF source for proper canvas sizing
|
|
39
|
+
* @param src - The GIF source URL
|
|
40
|
+
* @returns Promise resolving to width and height, or null if extraction fails
|
|
41
|
+
*/ export const getGifDimensions = async (src)=>{
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetch(src);
|
|
44
|
+
if (!response.ok) return null;
|
|
45
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
46
|
+
const uint8Array = new Uint8Array(arrayBuffer);
|
|
47
|
+
// Parse GIF header to get dimensions
|
|
48
|
+
if (uint8Array.length < 10) return null;
|
|
49
|
+
// GIF header: 6 bytes signature + 2 bytes width + 2 bytes height
|
|
50
|
+
const width = uint8Array[6] | uint8Array[7] << 8;
|
|
51
|
+
const height = uint8Array[8] | uint8Array[9] << 8;
|
|
52
|
+
return {
|
|
53
|
+
width,
|
|
54
|
+
height
|
|
55
|
+
};
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.warn('Failed to extract GIF dimensions:', error);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=gifUtils.js.map
|