inline-attacher 0.0.7 → 0.1.0

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 CHANGED
@@ -1,11 +1,13 @@
1
- # 📎 Inline Attachment Next (WIP)
1
+ # 📎 Inline Attacher
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/inline-attacher.svg?style=for-the-badge)](https://www.npmjs.com/package/inline-attacher)
4
4
  [![NPM Downloads](https://img.shields.io/npm/dt/inline-attacher.svg?style=for-the-badge)](https://www.npmjs.com/package/inline-attacher)
5
- [![License](https://img.shields.io/github/license/EastSun5566/inline-attachment.svg?style=for-the-badge)](https://github.com/EastSun5566/inline-attachment/blob/main/LICENSE)
5
+ [![License](https://img.shields.io/github/license/EastSun5566/inline-attacher.svg?style=for-the-badge)](https://github.com/EastSun5566/inline-attacher/blob/main/LICENSE)
6
6
 
7
7
  > A modern port of [Inline Attachment](https://github.com/Rovak/InlineAttachment)
8
8
 
9
+ 🔗 <https://eastsun5566.github.io/inline-attacher/>
10
+
9
11
  ## Installation
10
12
 
11
13
  ```sh
@@ -36,3 +38,27 @@ npm i inline-attacher
36
38
  parent: document.body,
37
39
  });
38
40
  ```
41
+
42
+ - Custom upload handler
43
+
44
+ ```ts
45
+ import { attach } from "inline-attacher";
46
+
47
+ const textarea = document.querySelector("textarea");
48
+
49
+ attach(textarea, {
50
+ async uploadHandler({ file, filename, formData }) {
51
+ const response = await myUploader.upload({
52
+ file,
53
+ filename,
54
+ formData,
55
+ });
56
+
57
+ return { url: response.publicUrl };
58
+ },
59
+ });
60
+ ```
61
+
62
+ The returned object is handled the same way as the built-in upload response:
63
+ `responseUrlKey` is used to read the uploaded file URL before replacing the
64
+ placeholder text.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,5 @@
1
- var w = Object.defineProperty;
2
- var x = (n, t, e) => t in n ? w(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
3
- var o = (n, t, e) => (x(n, typeof t != "symbol" ? t + "" : t, e), e);
4
- import { EditorView as D } from "@codemirror/view";
5
- const v = {
1
+ import { EditorView as w } from "@codemirror/view";
2
+ const m = {
6
3
  /**
7
4
  * URL where the file will be send
8
5
  */
@@ -90,7 +87,7 @@ const v = {
90
87
  onFileUploaded() {
91
88
  }
92
89
  };
93
- async function P({
90
+ async function U({
94
91
  url: n,
95
92
  ...t
96
93
  }) {
@@ -109,60 +106,74 @@ async function P({
109
106
  };
110
107
  }
111
108
  }
112
- function V(n) {
109
+ function x(n) {
113
110
  return typeof n == "function";
114
111
  }
115
- function T(n, t = "", e = "") {
116
- const r = t.split(".");
117
- let a = n;
118
- for (const s of r)
119
- if (a && typeof a == "object" && s in a)
120
- a = a[s];
112
+ function V(n, t = "", e = "") {
113
+ const i = t.split(".");
114
+ let r = n;
115
+ for (const o of i)
116
+ if (r && typeof r == "object" && o in r)
117
+ r = r[o];
121
118
  else
122
119
  return e;
123
- return a !== void 0 ? a : e;
120
+ return r !== void 0 ? r : e;
124
121
  }
125
122
  class E {
123
+ options = m;
124
+ editor;
125
+ filename = "";
126
+ lastValue = "";
126
127
  constructor(t, e) {
127
- o(this, "options", v);
128
- o(this, "editor");
129
- o(this, "filename", "");
130
- o(this, "lastValue", "");
131
- this.editor = t, this.options = { ...v, ...e };
128
+ this.editor = t, this.options = { ...m, ...e };
132
129
  }
133
130
  /** Uploads file */
134
131
  async uploadFile(t) {
135
132
  const {
136
133
  defaultExtension: e,
137
- remoteFilename: r,
138
- uploadFieldName: a,
139
- extraParams: s,
140
- extraHeaders: l,
141
- uploadUrl: d,
142
- uploadMethod: p,
143
- beforeFileUpload: c
144
- } = this.options, i = new FormData();
134
+ remoteFilename: i,
135
+ uploadFieldName: r,
136
+ extraParams: o,
137
+ extraHeaders: a,
138
+ uploadUrl: l,
139
+ uploadMethod: d,
140
+ beforeFileUpload: F,
141
+ uploadHandler: h
142
+ } = this.options, c = new FormData();
145
143
  let f = e;
146
144
  if (t.name) {
147
- const [u] = t.name.match(/\.(.+)$/) || [];
148
- u && (f = u);
145
+ const [s] = t.name.match(/\.(.+)$/) || [];
146
+ s && (f = s);
149
147
  }
150
- const g = (r == null ? void 0 : r(t)) || `image-${Date.now()}.${f}`;
151
- if (this.filename = g, i.append(a, t, g), Object.keys(s).forEach((u) => {
152
- i.append(u, s[u]);
153
- }), !(c != null && c(i)))
148
+ const u = i?.(t) || `image-${Date.now()}.${f}`;
149
+ if (this.filename = u, c.append(r, t, u), Object.keys(o).forEach((s) => {
150
+ c.append(s, o[s]);
151
+ }), !F?.(c)) return;
152
+ if (h) {
153
+ try {
154
+ const s = await h({
155
+ file: t,
156
+ filename: u,
157
+ formData: c,
158
+ options: this.options
159
+ });
160
+ this.onFileUploadSucceed(s);
161
+ } catch (s) {
162
+ this.onFileUploadError(s instanceof Error ? s : new Error(String(s)));
163
+ }
154
164
  return;
155
- const { ok: F, value: m } = await P({
156
- url: d,
157
- method: p,
158
- body: i,
159
- headers: l
165
+ }
166
+ const { ok: v, value: g } = await U({
167
+ url: l,
168
+ method: d,
169
+ body: c,
170
+ headers: a
160
171
  });
161
- if (!F) {
162
- this.onFileUploadError(m);
172
+ if (!v) {
173
+ this.onFileUploadError(g);
163
174
  return;
164
175
  }
165
- this.onFileUploadSucceed(m);
176
+ this.onFileUploadSucceed(g);
166
177
  }
167
178
  /**
168
179
  * Returns if the given file is allowed to handle
@@ -175,23 +186,16 @@ class E {
175
186
  * Handles upload response
176
187
  */
177
188
  onFileUploadSucceed(t) {
178
- var c, i;
179
- const { onFileUploadSucceed: e, urlText: r, responseUrlKey: a } = this.options;
180
- if (!(e != null && e(t)) || !this.lastValue)
181
- return;
182
- const s = T(t, a) || "unknown URL";
183
- if (!s)
184
- return;
185
- const l = /!\[({[^}]+})]\(([^)]+)\)/, d = V(r) ? r(s, t) : r.replace(r.match(l)[1], this.filename).replace(r.match(l)[2], s), p = this.editor.getValue().replace(this.lastValue, d);
186
- this.editor.setValue(p), (i = (c = this.options).onFileUploaded) == null || i.call(c, s);
189
+ const { onFileUploadSucceed: e, urlText: i, responseUrlKey: r } = this.options;
190
+ if (!e?.(t) || !this.lastValue) return;
191
+ const o = V(t, r) || "unknown URL", a = /!\[({[^}]+})]\(([^)]+)\)/, l = x(i) ? i(o, t) : i.replace(i.match(a)[1], this.filename).replace(i.match(a)[2], o), d = this.editor.getValue().replace(this.lastValue, l);
192
+ this.editor.setValue(d), this.options.onFileUploaded?.(o);
187
193
  }
188
194
  /**
189
195
  * Called when a file has failed to upload
190
196
  */
191
197
  onFileUploadError(t) {
192
- var r, a;
193
- if (!((a = (r = this.options).onFileUploadError) != null && a.call(r, t)) || !this.lastValue)
194
- return;
198
+ if (!this.options.onFileUploadError?.(t) || !this.lastValue) return;
195
199
  const e = this.editor.getValue().replace(this.lastValue, this.options.errorText);
196
200
  this.editor.setValue(e);
197
201
  }
@@ -199,8 +203,7 @@ class E {
199
203
  * Called when a file has been inserted, either by drop or paste
200
204
  */
201
205
  onFileInserted(t) {
202
- var e, r;
203
- (r = (e = this.options).onFileReceived) != null && r.call(e, t) && (this.lastValue = this.options.progressText, this.editor.insertValue(this.lastValue));
206
+ this.options.onFileReceived?.(t) && (this.lastValue = this.options.progressText, this.editor.insertValue(this.lastValue));
204
207
  }
205
208
  handleFiles(t) {
206
209
  Array.from(t).forEach((e) => {
@@ -211,75 +214,71 @@ class E {
211
214
  * Called when a paste event occurred
212
215
  */
213
216
  onPaste(t) {
214
- var e;
215
- t.preventDefault(), (e = t.clipboardData) != null && e.files.length && this.handleFiles(t.clipboardData.files);
217
+ t.clipboardData?.files.length && this.handleFiles(t.clipboardData.files);
216
218
  }
217
219
  /**
218
220
  * Called when a drop event occurred
219
221
  */
220
222
  onDrop(t) {
221
- var e;
222
- t.preventDefault(), (e = t.dataTransfer) != null && e.files.length && this.handleFiles(t.dataTransfer.files);
223
+ t.dataTransfer?.files.length && this.handleFiles(t.dataTransfer.files);
223
224
  }
224
225
  }
225
- function A(n, t) {
226
- const e = n.scrollTop;
227
- let r = 0, a = !1, s;
228
- n.selectionStart || n.selectionStart === 0 ? a = "ff" : document.selection && (a = "ie"), a === "ie" ? (n.focus(), s = document.selection.createRange(), s.moveStart("character", -n.value.length), r = s.text.length) : a === "ff" && (r = n.selectionStart || 0);
229
- const l = n.value.substring(0, r), d = n.value.substring(r, n.value.length);
230
- n.value = l + t + d, r += t.length, a === "ie" ? (n.focus(), s = document.selection.createRange(), s.moveStart("character", -n.value.length), s.moveStart("character", r), s.moveEnd("character", 0), s.select()) : a === "ff" && (n.selectionStart = r, n.selectionEnd = r, n.focus()), n.scrollTop = e;
226
+ function D(n, t) {
227
+ const e = n.scrollTop, i = n.selectionStart || 0, { value: r } = n, o = r.slice(0, i), a = r.slice(i, r.length);
228
+ n.value = o + t + a;
229
+ const l = i + t.length;
230
+ n.selectionStart = l, n.selectionEnd = l, n.scrollTop = e, n.focus();
231
231
  }
232
- class U {
232
+ class T {
233
+ instance;
233
234
  constructor(t) {
234
- o(this, "instance");
235
235
  this.instance = t;
236
236
  }
237
237
  getValue() {
238
238
  return this.instance.value;
239
239
  }
240
240
  insertValue(t) {
241
- A(this.instance, t);
241
+ D(this.instance, t), this.dispatchInputEvent();
242
242
  }
243
243
  setValue(t) {
244
- this.instance.value = t;
244
+ this.instance.value = t, this.dispatchInputEvent();
245
+ }
246
+ dispatchInputEvent() {
247
+ this.instance.dispatchEvent(new InputEvent("input", {
248
+ bubbles: !0,
249
+ cancelable: !0
250
+ }));
245
251
  }
246
252
  }
247
- class y extends E {
253
+ class b extends E {
248
254
  constructor(t, e = {}) {
249
- super(new U(t), e);
255
+ super(new T(t), e);
250
256
  }
251
257
  bind() {
252
258
  this.editor.instance.addEventListener(
253
259
  "paste",
254
260
  (t) => {
255
261
  this.onPaste(t);
256
- },
257
- !1
262
+ }
258
263
  ), this.editor.instance.addEventListener(
259
264
  "drop",
260
265
  (t) => {
261
- t.stopPropagation(), t.preventDefault(), this.onDrop(t);
262
- },
263
- !1
264
- ), this.editor.instance.addEventListener(
265
- "dragenter",
266
- (t) => {
267
- t.stopPropagation(), t.preventDefault();
266
+ t.preventDefault(), this.onDrop(t);
268
267
  }
269
268
  ), this.editor.instance.addEventListener(
270
269
  "dragover",
271
270
  (t) => {
272
- t.stopPropagation(), t.preventDefault();
271
+ t.preventDefault();
273
272
  }
274
273
  );
275
274
  }
276
275
  }
277
- function k(...n) {
278
- return new y(...n).bind();
276
+ function P(...n) {
277
+ return new b(...n).bind();
279
278
  }
280
- class b {
279
+ class y {
280
+ instance;
281
281
  constructor(t) {
282
- o(this, "instance");
283
282
  this.instance = t;
284
283
  }
285
284
  getValue() {
@@ -299,46 +298,39 @@ class b {
299
298
  }), this.instance.dispatch({ selection: { anchor: e } });
300
299
  }
301
300
  }
302
- class h extends E {
301
+ class p extends E {
303
302
  constructor(t, e = {}) {
304
- super(new b(t), e);
303
+ super(new y(t), e);
305
304
  }
306
305
  bind() {
307
306
  this.editor.instance.dom.addEventListener(
308
307
  "paste",
309
308
  (t) => {
310
309
  this.onPaste(t);
311
- },
312
- !1
310
+ }
313
311
  ), this.editor.instance.dom.addEventListener(
314
312
  "drop",
315
313
  (t) => {
316
- t.stopPropagation(), t.preventDefault(), this.onDrop(t);
317
- },
318
- !1
319
- ), this.editor.instance.dom.addEventListener(
320
- "dragenter",
321
- (t) => {
322
- t.stopPropagation(), t.preventDefault();
314
+ t.preventDefault(), this.onDrop(t);
323
315
  }
324
316
  ), this.editor.instance.dom.addEventListener(
325
317
  "dragover",
326
318
  (t) => {
327
- t.stopPropagation(), t.preventDefault();
319
+ t.preventDefault();
328
320
  }
329
321
  );
330
322
  }
331
323
  }
332
324
  function I(...n) {
333
- return new h(...n).bind();
325
+ return new p(...n).bind();
334
326
  }
335
- function M(n = {}) {
336
- return D.domEventHandlers({
327
+ function S(n = {}) {
328
+ return w.domEventHandlers({
337
329
  paste: (t, e) => {
338
- new h(e, n).onPaste(t);
330
+ new p(e, n).onPaste(t);
339
331
  },
340
332
  drop: (t, e) => {
341
- t.stopPropagation(), t.preventDefault(), new h(e, n).onDrop(t);
333
+ t.stopPropagation(), t.preventDefault(), new p(e, n).onDrop(t);
342
334
  },
343
335
  dragenter: (t) => {
344
336
  t.stopPropagation(), t.preventDefault();
@@ -349,11 +341,11 @@ function M(n = {}) {
349
341
  });
350
342
  }
351
343
  export {
352
- h as CodeMirrorInlineAttachmentAdapter,
353
- v as DEFAULT_OPTIONS,
344
+ p as CodeMirrorInlineAttachmentAdapter,
345
+ m as DEFAULT_OPTIONS,
354
346
  E as InlineAttachment,
355
- y as InputInlineAttachmentAdapter,
356
- k as attach,
347
+ b as InputInlineAttachmentAdapter,
348
+ P as attach,
357
349
  I as attachCodeMirror,
358
- M as inlineAttachmentExtension
350
+ S as inlineAttachmentExtension
359
351
  };
@@ -1 +1 @@
1
- (function(a,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("@codemirror/view")):typeof define=="function"&&define.amd?define(["exports","@codemirror/view"],s):(a=typeof globalThis<"u"?globalThis:a||self,s(a.inlineAttacher={},a.CodemirrorView))})(this,function(a,s){"use strict";var L=Object.defineProperty;var M=(a,s,l)=>s in a?L(a,s,{enumerable:!0,configurable:!0,writable:!0,value:l}):a[s]=l;var d=(a,s,l)=>(M(a,typeof s!="symbol"?s+"":s,l),l);const l={uploadUrl:"/upload",uploadMethod:"POST",uploadFieldName:"file",defaultExtension:"png",responseUrlKey:"url",allowedTypes:["image/jpeg","image/png","image/jpg","image/gif"],progressText:"![Uploading file...]()",urlText:"![{alt}]({url})",errorText:"Error uploading file",extraParams:{},extraHeaders:{},beforeFileUpload(){return!0},onFileReceived(){return!0},onFileUploadSucceed(){return!0},onFileUploadError(){return!0},onFileUploaded(){}};async function D({url:n,...t}){try{const e=await fetch(n,t);if(!e.ok)throw new Error(e.statusText);return{ok:!0,value:await e.json()}}catch(e){return{ok:!1,value:e}}}function T(n){return typeof n=="function"}function P(n,t="",e=""){const i=t.split(".");let r=n;for(const o of i)if(r&&typeof r=="object"&&o in r)r=r[o];else return e;return r!==void 0?r:e}class m{constructor(t,e){d(this,"options",l);d(this,"editor");d(this,"filename","");d(this,"lastValue","");this.editor=t,this.options={...l,...e}}async uploadFile(t){const{defaultExtension:e,remoteFilename:i,uploadFieldName:r,extraParams:o,extraHeaders:u,uploadUrl:p,uploadMethod:v,beforeFileUpload:h}=this.options,c=new FormData;let w=e;if(t.name){const[f]=t.name.match(/\.(.+)$/)||[];f&&(w=f)}const F=(i==null?void 0:i(t))||`image-${Date.now()}.${w}`;if(this.filename=F,c.append(r,t,F),Object.keys(o).forEach(f=>{c.append(f,o[f])}),!(h!=null&&h(c)))return;const{ok:I,value:A}=await D({url:p,method:v,body:c,headers:u});if(!I){this.onFileUploadError(A);return}this.onFileUploadSucceed(A)}isFileAllowed(t){const{allowedTypes:e}=this.options;return e.includes("*")||e.includes(t.type)}onFileUploadSucceed(t){var h,c;const{onFileUploadSucceed:e,urlText:i,responseUrlKey:r}=this.options;if(!(e!=null&&e(t))||!this.lastValue)return;const o=P(t,r)||"unknown URL";if(!o)return;const u=/!\[({[^}]+})]\(([^)]+)\)/,p=T(i)?i(o,t):i.replace(i.match(u)[1],this.filename).replace(i.match(u)[2],o),v=this.editor.getValue().replace(this.lastValue,p);this.editor.setValue(v),(c=(h=this.options).onFileUploaded)==null||c.call(h,o)}onFileUploadError(t){var i,r;if(!((r=(i=this.options).onFileUploadError)!=null&&r.call(i,t))||!this.lastValue)return;const e=this.editor.getValue().replace(this.lastValue,this.options.errorText);this.editor.setValue(e)}onFileInserted(t){var e,i;(i=(e=this.options).onFileReceived)!=null&&i.call(e,t)&&(this.lastValue=this.options.progressText,this.editor.insertValue(this.lastValue))}handleFiles(t){Array.from(t).forEach(e=>{this.isFileAllowed(e)&&(this.onFileInserted(e),this.uploadFile(e))})}onPaste(t){var e;t.preventDefault(),(e=t.clipboardData)!=null&&e.files.length&&this.handleFiles(t.clipboardData.files)}onDrop(t){var e;t.preventDefault(),(e=t.dataTransfer)!=null&&e.files.length&&this.handleFiles(t.dataTransfer.files)}}function V(n,t){const e=n.scrollTop;let i=0,r=!1,o;n.selectionStart||n.selectionStart===0?r="ff":document.selection&&(r="ie"),r==="ie"?(n.focus(),o=document.selection.createRange(),o.moveStart("character",-n.value.length),i=o.text.length):r==="ff"&&(i=n.selectionStart||0);const u=n.value.substring(0,i),p=n.value.substring(i,n.value.length);n.value=u+t+p,i+=t.length,r==="ie"?(n.focus(),o=document.selection.createRange(),o.moveStart("character",-n.value.length),o.moveStart("character",i),o.moveEnd("character",0),o.select()):r==="ff"&&(n.selectionStart=i,n.selectionEnd=i,n.focus()),n.scrollTop=e}class y{constructor(t){d(this,"instance");this.instance=t}getValue(){return this.instance.value}insertValue(t){V(this.instance,t)}setValue(t){this.instance.value=t}}class E extends m{constructor(t,e={}){super(new y(t),e)}bind(){this.editor.instance.addEventListener("paste",t=>{this.onPaste(t)},!1),this.editor.instance.addEventListener("drop",t=>{t.stopPropagation(),t.preventDefault(),this.onDrop(t)},!1),this.editor.instance.addEventListener("dragenter",t=>{t.stopPropagation(),t.preventDefault()}),this.editor.instance.addEventListener("dragover",t=>{t.stopPropagation(),t.preventDefault()})}}function x(...n){return new E(...n).bind()}class S{constructor(t){d(this,"instance");this.instance=t}getValue(){return this.instance.state.doc.toString()}insertValue(t){this.instance.dispatch(this.instance.state.replaceSelection(t))}setValue(t){const e=this.instance.state.selection.main.head;this.instance.dispatch({changes:{from:0,to:this.instance.state.doc.length,insert:t}}),this.instance.dispatch({selection:{anchor:e}})}}class g extends m{constructor(t,e={}){super(new S(t),e)}bind(){this.editor.instance.dom.addEventListener("paste",t=>{this.onPaste(t)},!1),this.editor.instance.dom.addEventListener("drop",t=>{t.stopPropagation(),t.preventDefault(),this.onDrop(t)},!1),this.editor.instance.dom.addEventListener("dragenter",t=>{t.stopPropagation(),t.preventDefault()}),this.editor.instance.dom.addEventListener("dragover",t=>{t.stopPropagation(),t.preventDefault()})}}function U(...n){return new g(...n).bind()}function b(n={}){return s.EditorView.domEventHandlers({paste:(t,e)=>{new g(e,n).onPaste(t)},drop:(t,e)=>{t.stopPropagation(),t.preventDefault(),new g(e,n).onDrop(t)},dragenter:t=>{t.stopPropagation(),t.preventDefault()},dragover:t=>{t.stopPropagation(),t.preventDefault()}})}a.CodeMirrorInlineAttachmentAdapter=g,a.DEFAULT_OPTIONS=l,a.InlineAttachment=m,a.InputInlineAttachmentAdapter=E,a.attach=x,a.attachCodeMirror=U,a.inlineAttachmentExtension=b,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})});
1
+ (function(o,d){typeof exports=="object"&&typeof module<"u"?d(exports,require("@codemirror/view")):typeof define=="function"&&define.amd?define(["exports","@codemirror/view"],d):(o=typeof globalThis<"u"?globalThis:o||self,d(o.inlineAttacher={},o.CodemirrorView))})(this,(function(o,d){"use strict";const h={uploadUrl:"/upload",uploadMethod:"POST",uploadFieldName:"file",defaultExtension:"png",responseUrlKey:"url",allowedTypes:["image/jpeg","image/png","image/jpg","image/gif"],progressText:"![Uploading file...]()",urlText:"![{alt}]({url})",errorText:"Error uploading file",extraParams:{},extraHeaders:{},beforeFileUpload(){return!0},onFileReceived(){return!0},onFileUploadSucceed(){return!0},onFileUploadError(){return!0},onFileUploaded(){}};async function A({url:n,...t}){try{const e=await fetch(n,t);if(!e.ok)throw new Error(e.statusText);return{ok:!0,value:await e.json()}}catch(e){return{ok:!1,value:e}}}function T(n){return typeof n=="function"}function U(n,t="",e=""){const i=t.split(".");let r=n;for(const s of i)if(r&&typeof r=="object"&&s in r)r=r[s];else return e;return r!==void 0?r:e}class f{options=h;editor;filename="";lastValue="";constructor(t,e){this.editor=t,this.options={...h,...e}}async uploadFile(t){const{defaultExtension:e,remoteFilename:i,uploadFieldName:r,extraParams:s,extraHeaders:l,uploadUrl:c,uploadMethod:m,beforeFileUpload:P,uploadHandler:F}=this.options,u=new FormData;let v=e;if(t.name){const[a]=t.name.match(/\.(.+)$/)||[];a&&(v=a)}const g=i?.(t)||`image-${Date.now()}.${v}`;if(this.filename=g,u.append(r,t,g),Object.keys(s).forEach(a=>{u.append(a,s[a])}),!P?.(u))return;if(F){try{const a=await F({file:t,filename:g,formData:u,options:this.options});this.onFileUploadSucceed(a)}catch(a){this.onFileUploadError(a instanceof Error?a:new Error(String(a)))}return}const{ok:S,value:w}=await A({url:c,method:m,body:u,headers:l});if(!S){this.onFileUploadError(w);return}this.onFileUploadSucceed(w)}isFileAllowed(t){const{allowedTypes:e}=this.options;return e.includes("*")||e.includes(t.type)}onFileUploadSucceed(t){const{onFileUploadSucceed:e,urlText:i,responseUrlKey:r}=this.options;if(!e?.(t)||!this.lastValue)return;const s=U(t,r)||"unknown URL",l=/!\[({[^}]+})]\(([^)]+)\)/,c=T(i)?i(s,t):i.replace(i.match(l)[1],this.filename).replace(i.match(l)[2],s),m=this.editor.getValue().replace(this.lastValue,c);this.editor.setValue(m),this.options.onFileUploaded?.(s)}onFileUploadError(t){if(!this.options.onFileUploadError?.(t)||!this.lastValue)return;const e=this.editor.getValue().replace(this.lastValue,this.options.errorText);this.editor.setValue(e)}onFileInserted(t){this.options.onFileReceived?.(t)&&(this.lastValue=this.options.progressText,this.editor.insertValue(this.lastValue))}handleFiles(t){Array.from(t).forEach(e=>{this.isFileAllowed(e)&&(this.onFileInserted(e),this.uploadFile(e))})}onPaste(t){t.clipboardData?.files.length&&this.handleFiles(t.clipboardData.files)}onDrop(t){t.dataTransfer?.files.length&&this.handleFiles(t.dataTransfer.files)}}function V(n,t){const e=n.scrollTop,i=n.selectionStart||0,{value:r}=n,s=r.slice(0,i),l=r.slice(i,r.length);n.value=s+t+l;const c=i+t.length;n.selectionStart=c,n.selectionEnd=c,n.scrollTop=e,n.focus()}class y{instance;constructor(t){this.instance=t}getValue(){return this.instance.value}insertValue(t){V(this.instance,t),this.dispatchInputEvent()}setValue(t){this.instance.value=t,this.dispatchInputEvent()}dispatchInputEvent(){this.instance.dispatchEvent(new InputEvent("input",{bubbles:!0,cancelable:!0}))}}class E extends f{constructor(t,e={}){super(new y(t),e)}bind(){this.editor.instance.addEventListener("paste",t=>{this.onPaste(t)}),this.editor.instance.addEventListener("drop",t=>{t.preventDefault(),this.onDrop(t)}),this.editor.instance.addEventListener("dragover",t=>{t.preventDefault()})}}function b(...n){return new E(...n).bind()}class D{instance;constructor(t){this.instance=t}getValue(){return this.instance.state.doc.toString()}insertValue(t){this.instance.dispatch(this.instance.state.replaceSelection(t))}setValue(t){const e=this.instance.state.selection.main.head;this.instance.dispatch({changes:{from:0,to:this.instance.state.doc.length,insert:t}}),this.instance.dispatch({selection:{anchor:e}})}}class p extends f{constructor(t,e={}){super(new D(t),e)}bind(){this.editor.instance.dom.addEventListener("paste",t=>{this.onPaste(t)}),this.editor.instance.dom.addEventListener("drop",t=>{t.preventDefault(),this.onDrop(t)}),this.editor.instance.dom.addEventListener("dragover",t=>{t.preventDefault()})}}function I(...n){return new p(...n).bind()}function x(n={}){return d.EditorView.domEventHandlers({paste:(t,e)=>{new p(e,n).onPaste(t)},drop:(t,e)=>{t.stopPropagation(),t.preventDefault(),new p(e,n).onDrop(t)},dragenter:t=>{t.stopPropagation(),t.preventDefault()},dragover:t=>{t.stopPropagation(),t.preventDefault()}})}o.CodeMirrorInlineAttachmentAdapter=p,o.DEFAULT_OPTIONS=h,o.InlineAttachment=f,o.InputInlineAttachmentAdapter=E,o.attach=b,o.attachCodeMirror=I,o.inlineAttachmentExtension=x,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})}));
package/dist/types.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ export interface UploadHandlerContext {
2
+ file: File;
3
+ filename: string;
4
+ formData: FormData;
5
+ options: InlineAttachmentOptions;
6
+ }
1
7
  export interface InlineAttachmentOptions {
2
8
  uploadUrl: string;
3
9
  uploadMethod: string;
@@ -15,6 +21,7 @@ export interface InlineAttachmentOptions {
15
21
  [name: string]: any;
16
22
  };
17
23
  beforeFileUpload?: (formData: FormData) => boolean;
24
+ uploadHandler?: (context: UploadHandlerContext) => Promise<Record<string, unknown>> | Record<string, unknown>;
18
25
  remoteFilename?: (file: File) => string;
19
26
  onFileReceived?: (file: File) => boolean;
20
27
  onFileUploadSucceed?: (response: Record<string, unknown>) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inline-attacher",
3
- "version": "0.0.7",
3
+ "version": "0.1.0",
4
4
  "description": "📎 A modern port from Inline Attachment",
5
5
  "type": "module",
6
6
  "files": [
@@ -11,10 +11,23 @@
11
11
  "types": "./dist/index.d.ts",
12
12
  "exports": {
13
13
  ".": {
14
+ "types": "./dist/index.d.ts",
14
15
  "import": "./dist/inline-attacher.js",
15
16
  "require": "./dist/inline-attacher.umd.cjs"
16
17
  }
17
18
  },
19
+ "scripts": {
20
+ "dev": "vite",
21
+ "build": "rimraf dist && tsc && vite build",
22
+ "preview": "vite preview",
23
+ "test": "vitest run",
24
+ "playground:dev": "pnpm -C playground dev",
25
+ "playground:deploy": "pnpm -C playground run deploy",
26
+ "lint": "eslint --fix --ext .ts src",
27
+ "prepublishOnly": "pnpm build",
28
+ "release": "pnpx standard-version && git push --follow-tags && pnpm publish",
29
+ "size-check": "pnpx vite-bundle-visualizer"
30
+ },
18
31
  "keywords": [
19
32
  "inline-attachment",
20
33
  "attachment",
@@ -24,7 +37,7 @@
24
37
  "image",
25
38
  "file"
26
39
  ],
27
- "author": "Michael Wang 汪東陽 <michael19920327@gmail.com> (https://github.com/EastSun5566)",
40
+ "author": "Michael Wang <hi@eastsun.me> (https://github.com/EastSun5566)",
28
41
  "license": "MIT",
29
42
  "repository": {
30
43
  "type": "git",
@@ -34,36 +47,29 @@
34
47
  "url": "https://github.com/EastSun5566/inline-attachment/issues/new"
35
48
  },
36
49
  "homepage": "https://github.com/EastSun5566/inline-attachment",
37
- "packageManager": "pnpm@8.6.0",
50
+ "packageManager": "pnpm@10.34.4",
38
51
  "engines": {
39
- "node": ">=16.0.0",
40
- "pnpm": ">=7.0.0"
52
+ "node": ">=22"
41
53
  },
42
54
  "peerDependencies": {
43
55
  "@codemirror/view": ">=6.0.0"
44
56
  },
45
57
  "devDependencies": {
46
- "@codemirror/state": "^6.2.1",
47
- "@types/node": "^20.5.0",
48
- "@typescript-eslint/eslint-plugin": "^6.4.0",
49
- "@typescript-eslint/parser": "^6.4.0",
50
- "eslint": "^8.47.0",
58
+ "@codemirror/state": "^6.7.0",
59
+ "@types/node": "^22.20.0",
60
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
61
+ "@typescript-eslint/parser": "^6.21.0",
62
+ "eslint": "^8.57.1",
51
63
  "eslint-config-airbnb-base": "^15.0.0",
52
64
  "eslint-config-airbnb-typescript": "^17.1.0",
53
- "eslint-plugin-import": "^2.28.0",
54
- "rimraf": "^5.0.1",
55
- "typescript": "^5.1.6",
56
- "vite": "^4.4.9"
65
+ "eslint-plugin-import": "^2.31.0",
66
+ "happy-dom": "^20.0.2",
67
+ "rimraf": "^5.0.10",
68
+ "typescript": "^6.0.2",
69
+ "vite": "^7.3.0",
70
+ "vitest": "^4.0.16"
57
71
  },
58
72
  "dependencies": {
59
- "@codemirror/view": "^6.16.0"
60
- },
61
- "scripts": {
62
- "dev": "vite",
63
- "build": "rimraf dist && tsc && vite build",
64
- "preview": "vite preview",
65
- "playground:dev": "pnpm -C playground dev",
66
- "lint": "eslint --fix --ext .ts src",
67
- "release": "pnpx standard-version && git push --follow-tags && pnpm publish"
73
+ "@codemirror/view": "^6.43.4"
68
74
  }
69
- }
75
+ }