@examplary/ui 0.0.1
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 +3 -0
- package/dist/components/button.d.ts +11 -0
- package/dist/components/button.js +58 -0
- package/dist/components/input.d.ts +4 -0
- package/dist/components/input.js +31 -0
- package/dist/components/rich-text/index.d.ts +5 -0
- package/dist/components/rich-text/index.js +5 -0
- package/dist/components/rich-text/minimal-rich-text-field.d.ts +17 -0
- package/dist/components/rich-text/minimal-rich-text-field.js +99 -0
- package/dist/components/rich-text/rich-text-display.d.ts +13 -0
- package/dist/components/rich-text/rich-text-display.js +38 -0
- package/dist/components/rich-text/rich-text-input.d.ts +14 -0
- package/dist/components/rich-text/rich-text-input.js +31 -0
- package/dist/components/rich-text/rich-text-toolbar.d.ts +3 -0
- package/dist/components/rich-text/rich-text-toolbar.js +33 -0
- package/dist/components/rich-text/tiptap/file-attachment.d.ts +3 -0
- package/dist/components/rich-text/tiptap/file-attachment.js +40 -0
- package/dist/components/rich-text/tiptap/file-handler.d.ts +4 -0
- package/dist/components/rich-text/tiptap/file-handler.js +196 -0
- package/dist/components/rich-text/tiptap/image.d.ts +51 -0
- package/dist/components/rich-text/tiptap/image.js +88 -0
- package/dist/components/rich-text/tiptap/page-clipping.d.ts +3 -0
- package/dist/components/rich-text/tiptap/page-clipping.js +54 -0
- package/dist/components/rich-text/tiptap/png-scanner.d.ts +6 -0
- package/dist/components/rich-text/tiptap/png-scanner.js +208 -0
- package/dist/components/rich-text/tiptap/rich-text-formatting-menu.d.ts +3 -0
- package/dist/components/rich-text/tiptap/rich-text-formatting-menu.js +34 -0
- package/dist/components/web-components/file-attachment.d.ts +12 -0
- package/dist/components/web-components/file-attachment.js +40 -0
- package/dist/components/web-components/index.d.ts +3 -0
- package/dist/components/web-components/index.js +12 -0
- package/dist/components/web-components/page-clipping.d.ts +4 -0
- package/dist/components/web-components/page-clipping.js +41 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +9 -0
- package/package.json +40 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Node } from "@tiptap/core";
|
|
2
|
+
export interface ImageOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Controls if the image node should be inline or not.
|
|
5
|
+
* @default false
|
|
6
|
+
* @example true
|
|
7
|
+
*/
|
|
8
|
+
inline: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Controls if base64 images are allowed. Enable this if you want to allow
|
|
11
|
+
* base64 image urls in the `src` attribute.
|
|
12
|
+
* @default false
|
|
13
|
+
* @example true
|
|
14
|
+
*/
|
|
15
|
+
allowBase64: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* HTML attributes to add to the image element.
|
|
18
|
+
* @default {}
|
|
19
|
+
* @example { class: 'foo' }
|
|
20
|
+
*/
|
|
21
|
+
HTMLAttributes: Record<string, any>;
|
|
22
|
+
}
|
|
23
|
+
declare module "@tiptap/core" {
|
|
24
|
+
interface Commands<ReturnType> {
|
|
25
|
+
image: {
|
|
26
|
+
/**
|
|
27
|
+
* Add an image
|
|
28
|
+
* @param options The image attributes
|
|
29
|
+
* @example
|
|
30
|
+
* editor
|
|
31
|
+
* .commands
|
|
32
|
+
* .setImage({ src: 'https://tiptap.dev/logo.png', alt: 'tiptap', title: 'tiptap logo' })
|
|
33
|
+
*/
|
|
34
|
+
setImage: (options: {
|
|
35
|
+
src: string;
|
|
36
|
+
alt?: string;
|
|
37
|
+
title?: string;
|
|
38
|
+
}) => ReturnType;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Matches an image to a  on input.
|
|
44
|
+
*/
|
|
45
|
+
export declare const inputRegex: RegExp;
|
|
46
|
+
/**
|
|
47
|
+
* This extension allows you to insert images.
|
|
48
|
+
* @see https://www.tiptap.dev/api/nodes/image
|
|
49
|
+
*/
|
|
50
|
+
declare const Image: Node<ImageOptions, any>;
|
|
51
|
+
export default Image;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { mergeAttributes, Node, nodeInputRule } from "@tiptap/core";
|
|
2
|
+
/**
|
|
3
|
+
* Matches an image to a  on input.
|
|
4
|
+
*/
|
|
5
|
+
export var inputRegex = /(?:^|\s)(!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\))$/;
|
|
6
|
+
/**
|
|
7
|
+
* This extension allows you to insert images.
|
|
8
|
+
* @see https://www.tiptap.dev/api/nodes/image
|
|
9
|
+
*/
|
|
10
|
+
var Image = Node.create({
|
|
11
|
+
name: "image",
|
|
12
|
+
addOptions: function () {
|
|
13
|
+
return {
|
|
14
|
+
inline: false,
|
|
15
|
+
allowBase64: false,
|
|
16
|
+
HTMLAttributes: {},
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
inline: function () {
|
|
20
|
+
return this.options.inline;
|
|
21
|
+
},
|
|
22
|
+
group: function () {
|
|
23
|
+
return this.options.inline ? "inline" : "block";
|
|
24
|
+
},
|
|
25
|
+
draggable: true,
|
|
26
|
+
addAttributes: function () {
|
|
27
|
+
return {
|
|
28
|
+
src: {
|
|
29
|
+
default: null,
|
|
30
|
+
},
|
|
31
|
+
alt: {
|
|
32
|
+
default: null,
|
|
33
|
+
},
|
|
34
|
+
title: {
|
|
35
|
+
default: null,
|
|
36
|
+
},
|
|
37
|
+
width: {
|
|
38
|
+
default: null,
|
|
39
|
+
},
|
|
40
|
+
height: {
|
|
41
|
+
default: null,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
parseHTML: function () {
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
tag: this.options.allowBase64
|
|
49
|
+
? "img[src]"
|
|
50
|
+
: 'img[src]:not([src^="data:"])',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
},
|
|
54
|
+
renderHTML: function (_a) {
|
|
55
|
+
var HTMLAttributes = _a.HTMLAttributes;
|
|
56
|
+
return [
|
|
57
|
+
"img",
|
|
58
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
|
59
|
+
];
|
|
60
|
+
},
|
|
61
|
+
addCommands: function () {
|
|
62
|
+
var _this = this;
|
|
63
|
+
return {
|
|
64
|
+
setImage: function (options) {
|
|
65
|
+
return function (_a) {
|
|
66
|
+
var commands = _a.commands;
|
|
67
|
+
return commands.insertContent({
|
|
68
|
+
type: _this.name,
|
|
69
|
+
attrs: options,
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
addInputRules: function () {
|
|
76
|
+
return [
|
|
77
|
+
nodeInputRule({
|
|
78
|
+
find: inputRegex,
|
|
79
|
+
type: this.type,
|
|
80
|
+
getAttributes: function (match) {
|
|
81
|
+
var alt = match[2], src = match[3], title = match[4];
|
|
82
|
+
return { src: src, alt: alt, title: title };
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
];
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
export default Image;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import { mergeAttributes, Node } from "@tiptap/core";
|
|
14
|
+
import { createRoot } from "react-dom/client";
|
|
15
|
+
import { PageClippingView } from "../../web-components/page-clipping";
|
|
16
|
+
export default Node.create({
|
|
17
|
+
name: "page-clipping",
|
|
18
|
+
group: "block",
|
|
19
|
+
content: "inline*",
|
|
20
|
+
atom: true,
|
|
21
|
+
addAttributes: function () {
|
|
22
|
+
return {
|
|
23
|
+
url: {},
|
|
24
|
+
page: {},
|
|
25
|
+
x: {},
|
|
26
|
+
y: {},
|
|
27
|
+
width: {},
|
|
28
|
+
height: {},
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
parseHTML: function () {
|
|
32
|
+
return [
|
|
33
|
+
{
|
|
34
|
+
tag: "page-clipping",
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
},
|
|
38
|
+
renderHTML: function (_a) {
|
|
39
|
+
var HTMLAttributes = _a.HTMLAttributes;
|
|
40
|
+
return ["page-clipping", mergeAttributes(HTMLAttributes)];
|
|
41
|
+
},
|
|
42
|
+
addNodeView: function () {
|
|
43
|
+
return function (_a) {
|
|
44
|
+
var node = _a.node;
|
|
45
|
+
var dom = document.createElement("div");
|
|
46
|
+
dom.classList.add("page-clipping");
|
|
47
|
+
var root = createRoot(dom);
|
|
48
|
+
root.render(_jsx(PageClippingView, __assign({}, node.attrs)));
|
|
49
|
+
return {
|
|
50
|
+
dom: dom,
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
});
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Class to scan PNG files and extract metadata
|
|
39
|
+
*/
|
|
40
|
+
var PNGScanner = /** @class */ (function () {
|
|
41
|
+
function PNGScanner(buffer) {
|
|
42
|
+
this.dataview = new DataView(buffer);
|
|
43
|
+
this.pos = 0;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Advance the position pointer
|
|
47
|
+
*/
|
|
48
|
+
PNGScanner.prototype.advance = function (bytes) {
|
|
49
|
+
this.pos += bytes;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Read an integer of specified byte length
|
|
53
|
+
*/
|
|
54
|
+
PNGScanner.prototype.readInt = function (bytes) {
|
|
55
|
+
var value;
|
|
56
|
+
switch (bytes) {
|
|
57
|
+
case 1:
|
|
58
|
+
value = this.dataview.getUint8(this.pos);
|
|
59
|
+
break;
|
|
60
|
+
case 2:
|
|
61
|
+
value = this.dataview.getUint16(this.pos);
|
|
62
|
+
break;
|
|
63
|
+
case 4:
|
|
64
|
+
value = this.dataview.getUint32(this.pos);
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
throw Error("bytes parameter must be 1, 2 or 4");
|
|
68
|
+
}
|
|
69
|
+
this.advance(bytes);
|
|
70
|
+
return value;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Read a single byte as a character
|
|
74
|
+
*/
|
|
75
|
+
PNGScanner.prototype.readChar = function () {
|
|
76
|
+
return this.readInt(1);
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Read a 2-byte short integer
|
|
80
|
+
*/
|
|
81
|
+
PNGScanner.prototype.readShort = function () {
|
|
82
|
+
return this.readInt(2);
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Read a 4-byte long integer
|
|
86
|
+
*/
|
|
87
|
+
PNGScanner.prototype.readLong = function () {
|
|
88
|
+
return this.readInt(4);
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Read a string of specified length
|
|
92
|
+
*/
|
|
93
|
+
PNGScanner.prototype.readString = function (length) {
|
|
94
|
+
var chars = [];
|
|
95
|
+
for (var i = 0; i < length; i++) {
|
|
96
|
+
chars.push(String.fromCharCode(this.readChar()));
|
|
97
|
+
}
|
|
98
|
+
return chars.join("");
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Scan through PNG chunks and call the provided callback for each chunk
|
|
102
|
+
*/
|
|
103
|
+
PNGScanner.prototype.scan = function (callback) {
|
|
104
|
+
// Check PNG signature
|
|
105
|
+
if (0x89504e47 !== this.readLong()) {
|
|
106
|
+
throw Error("invalid PNG");
|
|
107
|
+
}
|
|
108
|
+
// Skip the rest of the header
|
|
109
|
+
this.advance(4);
|
|
110
|
+
// Process chunks
|
|
111
|
+
while (true) {
|
|
112
|
+
var chunkLength = this.readLong();
|
|
113
|
+
var chunkType = this.readString(4);
|
|
114
|
+
var nextChunkPos = this.pos + chunkLength + 4;
|
|
115
|
+
if (callback.call(this, chunkType, chunkLength) === false ||
|
|
116
|
+
chunkType === "IEND") {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
this.pos = nextChunkPos;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
return PNGScanner;
|
|
123
|
+
}());
|
|
124
|
+
/**
|
|
125
|
+
* Parse PNG metadata from a buffer
|
|
126
|
+
*/
|
|
127
|
+
var parsePNGMetadata = function (buffer) {
|
|
128
|
+
var scanner = new PNGScanner(buffer);
|
|
129
|
+
var metadata = {
|
|
130
|
+
width: 0,
|
|
131
|
+
height: 0,
|
|
132
|
+
ppi: 1,
|
|
133
|
+
};
|
|
134
|
+
scanner.scan(function (chunkType) {
|
|
135
|
+
switch (chunkType) {
|
|
136
|
+
case "IHDR":
|
|
137
|
+
metadata.width = this.readLong();
|
|
138
|
+
metadata.height = this.readLong();
|
|
139
|
+
break;
|
|
140
|
+
case "pHYs": {
|
|
141
|
+
var metersToInches = void 0;
|
|
142
|
+
var xPixelsPerUnit = this.readLong();
|
|
143
|
+
var yPixelsPerUnit = this.readLong();
|
|
144
|
+
// Check if units are meters (1)
|
|
145
|
+
if (this.readChar() === 1) {
|
|
146
|
+
metersToInches = 0.0254; // Conversion factor from meters to inches
|
|
147
|
+
}
|
|
148
|
+
if (metersToInches) {
|
|
149
|
+
// Calculate pixels per inch (PPI)
|
|
150
|
+
metadata.ppi = Math.round(((xPixelsPerUnit + yPixelsPerUnit) / 2) * metersToInches);
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
case "IDAT":
|
|
155
|
+
return false; // Stop scanning when we reach image data
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
});
|
|
159
|
+
return metadata;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Read a file as ArrayBuffer and extract PNG metadata
|
|
163
|
+
*/
|
|
164
|
+
var extractPNGMetadata = function (file) { return __awaiter(void 0, void 0, void 0, function () {
|
|
165
|
+
var buffer, error_1;
|
|
166
|
+
return __generator(this, function (_a) {
|
|
167
|
+
switch (_a.label) {
|
|
168
|
+
case 0:
|
|
169
|
+
_a.trys.push([0, 2, , 3]);
|
|
170
|
+
return [4 /*yield*/, new Promise(function (resolve, reject) {
|
|
171
|
+
var reader = new FileReader();
|
|
172
|
+
reader.onload = function () { return resolve(reader.result); };
|
|
173
|
+
reader.onerror = function () { return reject(reader.error); };
|
|
174
|
+
reader.readAsArrayBuffer(file);
|
|
175
|
+
})];
|
|
176
|
+
case 1:
|
|
177
|
+
buffer = _a.sent();
|
|
178
|
+
return [2 /*return*/, buffer ? parsePNGMetadata(buffer) : null];
|
|
179
|
+
case 2:
|
|
180
|
+
error_1 = _a.sent();
|
|
181
|
+
console.error("Error reading PNG file:", error_1);
|
|
182
|
+
return [2 /*return*/, null];
|
|
183
|
+
case 3: return [2 /*return*/];
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}); };
|
|
187
|
+
/**
|
|
188
|
+
* Get the actual width of an image, accounting for high DPI images
|
|
189
|
+
*/
|
|
190
|
+
export var getImageSize = function (file) { return __awaiter(void 0, void 0, void 0, function () {
|
|
191
|
+
var metadata, actualWidth;
|
|
192
|
+
return __generator(this, function (_a) {
|
|
193
|
+
switch (_a.label) {
|
|
194
|
+
case 0: return [4 /*yield*/, extractPNGMetadata(file)];
|
|
195
|
+
case 1:
|
|
196
|
+
metadata = _a.sent();
|
|
197
|
+
if (!metadata) {
|
|
198
|
+
return [2 /*return*/, { width: 0 }];
|
|
199
|
+
}
|
|
200
|
+
// For high DPI images (e.g., 144 PPI which is common for 2x retina displays)
|
|
201
|
+
if (metadata.ppi === 144) {
|
|
202
|
+
actualWidth = Math.round(metadata.width / 2);
|
|
203
|
+
return [2 /*return*/, { width: actualWidth }];
|
|
204
|
+
}
|
|
205
|
+
return [2 /*return*/, { width: metadata.width }];
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}); };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from "react";
|
|
3
|
+
import { BubbleMenu } from "@tiptap/react/menus";
|
|
4
|
+
import { Bold, Highlighter, Italic, LinkIcon, List, TextQuote, } from "lucide-react";
|
|
5
|
+
import { cn } from "../../../utils";
|
|
6
|
+
export var RichTextFormattingMenu = function (_a) {
|
|
7
|
+
var editor = _a.editor;
|
|
8
|
+
var setLink = useCallback(function () {
|
|
9
|
+
if (editor.isActive("link")) {
|
|
10
|
+
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
var previousUrl = editor.getAttributes("link").href;
|
|
14
|
+
var url = window.prompt("Where do you want to link to? Enter a link that starts with 'https://'.", previousUrl);
|
|
15
|
+
// cancelled
|
|
16
|
+
if (url === null) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
// empty
|
|
20
|
+
if (url === "") {
|
|
21
|
+
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (url.indexOf("http") !== 0) {
|
|
25
|
+
url = "http://" + url;
|
|
26
|
+
}
|
|
27
|
+
// update link
|
|
28
|
+
editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
|
|
29
|
+
}, [editor]);
|
|
30
|
+
if (!editor) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return (_jsx(BubbleMenu, { editor: editor, children: _jsxs("div", { className: "border-2 p-0.5 gap-0.5 bg-white rounded-md flex items-center shadow-md", children: [_jsx("span", { onClick: function () { return editor.chain().focus().toggleBold().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("bold") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(Bold, { size: 16, strokeWidth: editor.isActive("bold") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleItalic().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("italic") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(Italic, { size: 16, strokeWidth: editor.isActive("italic") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleHighlight().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("highlight") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(Highlighter, { size: 16, strokeWidth: editor.isActive("highlight") ? 2.75 : 2 }) }), _jsx("span", { onClick: setLink, className: cn("p-1 cursor-pointer", editor.isActive("link") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(LinkIcon, { size: 16, strokeWidth: editor.isActive("link") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBulletList().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("bulletList") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(List, { size: 16, strokeWidth: editor.isActive("bulletList") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleOrderedList().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("orderedList") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(List, { size: 16, strokeWidth: editor.isActive("orderedList") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBlockquote().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("blockquote") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(TextQuote, { size: 16, strokeWidth: editor.isActive("blockquote") ? 2.75 : 2 }) })] }) }));
|
|
34
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface FileAttachmentProps {
|
|
3
|
+
title: string;
|
|
4
|
+
type?: string;
|
|
5
|
+
href: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const FileAttachmentView: React.FC<FileAttachmentProps>;
|
|
9
|
+
export declare class FileAttachmentElement extends HTMLElement {
|
|
10
|
+
connectedCallback(): void;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
var __extends = (this && this.__extends) || (function () {
|
|
2
|
+
var extendStatics = function (d, b) {
|
|
3
|
+
extendStatics = Object.setPrototypeOf ||
|
|
4
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
6
|
+
return extendStatics(d, b);
|
|
7
|
+
};
|
|
8
|
+
return function (d, b) {
|
|
9
|
+
if (typeof b !== "function" && b !== null)
|
|
10
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
11
|
+
extendStatics(d, b);
|
|
12
|
+
function __() { this.constructor = d; }
|
|
13
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
14
|
+
};
|
|
15
|
+
})();
|
|
16
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
17
|
+
import { FileIcon } from "lucide-react";
|
|
18
|
+
import { createRoot } from "react-dom/client";
|
|
19
|
+
import { cn } from "../../utils";
|
|
20
|
+
export var FileAttachmentView = function (_a) {
|
|
21
|
+
var title = _a.title, href = _a.href, className = _a.className;
|
|
22
|
+
return (_jsxs("a", { href: href, target: "_blank", rel: "noopener noreferrer", className: cn("flex items-center gap-1.5 mt-1.5 py-1 rounded-base text-sm font-medium", className), children: [_jsx(FileIcon, { className: "size-4 flex-shrink-0" }), _jsx("span", { className: "truncate", children: title })] }));
|
|
23
|
+
};
|
|
24
|
+
// Custom element for use in rich text editors
|
|
25
|
+
var FileAttachmentElement = /** @class */ (function (_super) {
|
|
26
|
+
__extends(FileAttachmentElement, _super);
|
|
27
|
+
function FileAttachmentElement() {
|
|
28
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
29
|
+
}
|
|
30
|
+
FileAttachmentElement.prototype.connectedCallback = function () {
|
|
31
|
+
var title = this.getAttribute("title") || "File";
|
|
32
|
+
var type = this.getAttribute("type") || "";
|
|
33
|
+
var href = this.getAttribute("href") || "#";
|
|
34
|
+
// Create React root and render component
|
|
35
|
+
var root = createRoot(this);
|
|
36
|
+
root.render(_jsx(FileAttachmentView, { title: title, type: type, href: href }));
|
|
37
|
+
};
|
|
38
|
+
return FileAttachmentElement;
|
|
39
|
+
}(HTMLElement));
|
|
40
|
+
export { FileAttachmentElement };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FileAttachmentElement } from "./file-attachment";
|
|
2
|
+
import { PageClippingElement } from "./page-clipping";
|
|
3
|
+
export * from "./file-attachment";
|
|
4
|
+
export * from "./page-clipping";
|
|
5
|
+
export var registerWebComponents = function () {
|
|
6
|
+
if (typeof window !== "undefined" && !customElements.get("page-clipping")) {
|
|
7
|
+
customElements.define("page-clipping", PageClippingElement);
|
|
8
|
+
}
|
|
9
|
+
if (typeof window !== "undefined" && !customElements.get("file-attachment")) {
|
|
10
|
+
customElements.define("file-attachment", FileAttachmentElement);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var __extends = (this && this.__extends) || (function () {
|
|
2
|
+
var extendStatics = function (d, b) {
|
|
3
|
+
extendStatics = Object.setPrototypeOf ||
|
|
4
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
6
|
+
return extendStatics(d, b);
|
|
7
|
+
};
|
|
8
|
+
return function (d, b) {
|
|
9
|
+
if (typeof b !== "function" && b !== null)
|
|
10
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
11
|
+
extendStatics(d, b);
|
|
12
|
+
function __() { this.constructor = d; }
|
|
13
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
14
|
+
};
|
|
15
|
+
})();
|
|
16
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
17
|
+
import { createRoot } from "react-dom/client";
|
|
18
|
+
export var PageClippingView = function (props) {
|
|
19
|
+
// TODO: hardcoded API base URL
|
|
20
|
+
return (_jsx("img", { src: "https://api.examplary.ai/public/page-clippings?".concat(new URLSearchParams(props)), alt: "Page Clipping" }));
|
|
21
|
+
};
|
|
22
|
+
// Custom element for use in rich text editors
|
|
23
|
+
var PageClippingElement = /** @class */ (function (_super) {
|
|
24
|
+
__extends(PageClippingElement, _super);
|
|
25
|
+
function PageClippingElement() {
|
|
26
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
27
|
+
}
|
|
28
|
+
PageClippingElement.prototype.connectedCallback = function () {
|
|
29
|
+
var url = this.getAttribute("url") || "";
|
|
30
|
+
var page = this.getAttribute("page") || "";
|
|
31
|
+
var x = this.getAttribute("x") || "";
|
|
32
|
+
var y = this.getAttribute("y") || "";
|
|
33
|
+
var width = this.getAttribute("width") || "";
|
|
34
|
+
var height = this.getAttribute("height") || "";
|
|
35
|
+
// Create React root and render component
|
|
36
|
+
var root = createRoot(this);
|
|
37
|
+
root.render(_jsx(PageClippingView, { url: url, page: page, x: x, y: y, width: width, height: height }));
|
|
38
|
+
};
|
|
39
|
+
return PageClippingElement;
|
|
40
|
+
}(HTMLElement));
|
|
41
|
+
export { PageClippingElement };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cn(...inputs: (string | null | boolean | undefined)[]): string;
|
package/dist/utils.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@examplary/ui",
|
|
3
|
+
"description": "UI components for the Examplary testing platform.",
|
|
4
|
+
"packageManager": "yarn@4.5.3",
|
|
5
|
+
"version": "0.0.1",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"start": "yarn build --watch",
|
|
13
|
+
"build": "tsc ./src/index.ts --outDir dist --skipLibCheck --declaration --jsx react-jsx --esModuleInterop --moduleResolution bundler --module es2020",
|
|
14
|
+
"release": "semantic-release -e semantic-release-monorepo"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@floating-ui/dom": "^1.7.2",
|
|
18
|
+
"@tailwindcss/forms": "^0.5.10",
|
|
19
|
+
"@tailwindcss/typography": "^0.5.16",
|
|
20
|
+
"@tiptap-pro/extension-file-handler": "^2.21.5",
|
|
21
|
+
"@tiptap-pro/extension-mathematics": "^2.18.0",
|
|
22
|
+
"@tiptap/core": "^3.0.7",
|
|
23
|
+
"@tiptap/extension-highlight": "^3.0.7",
|
|
24
|
+
"@tiptap/extension-link": "^3.0.7",
|
|
25
|
+
"@tiptap/extension-mathematics": "^3.0.7",
|
|
26
|
+
"@tiptap/extension-placeholder": "^3.0.7",
|
|
27
|
+
"@tiptap/extension-typography": "^3.0.7",
|
|
28
|
+
"@tiptap/react": "^3.0.7",
|
|
29
|
+
"@tiptap/starter-kit": "^3.0.7",
|
|
30
|
+
"clsx": "^2.1.1",
|
|
31
|
+
"katex": "^0.16.22",
|
|
32
|
+
"lucide-react": "^0.525.0",
|
|
33
|
+
"tailwind-animate": "^0.2.10",
|
|
34
|
+
"tailwind-merge": "^3.3.1",
|
|
35
|
+
"tailwindcss-animate": "^1.0.7"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "^5.8.3"
|
|
39
|
+
}
|
|
40
|
+
}
|