@jinntec/jinntap 1.32.0 → 1.33.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.
@@ -1,12 +1,33 @@
1
- class l extends HTMLElement {
1
+ function g(h, e = {}) {
2
+ const { confirmLabel: o = "OK", cancelLabel: i = "Cancel", type: n = "info", nohtml: t = !1 } = e;
3
+ return new Promise((a) => {
4
+ document.dispatchEvent(
5
+ new CustomEvent("jinn-toast", {
6
+ detail: {
7
+ message: h,
8
+ type: n,
9
+ nohtml: t,
10
+ sticky: !0,
11
+ confirm: {
12
+ confirmLabel: o,
13
+ cancelLabel: i,
14
+ onConfirm: () => a(!0),
15
+ onCancel: () => a(!1)
16
+ }
17
+ }
18
+ })
19
+ );
20
+ });
21
+ }
22
+ class v extends HTMLElement {
2
23
  constructor() {
3
24
  super(), this.duration = 3e3, this.stickyDuration = 3e4;
4
25
  }
5
26
  static get observedAttributes() {
6
27
  return ["duration"];
7
28
  }
8
- attributeChangedCallback(t, a, i) {
9
- t === "duration" && (this.duration = parseInt(i) || 3e3);
29
+ attributeChangedCallback(e, o, i) {
30
+ e === "duration" && (this.duration = parseInt(i) || 3e3);
10
31
  }
11
32
  connectedCallback() {
12
33
  this.render(), this.setupEventListeners();
@@ -46,10 +67,53 @@ class l extends HTMLElement {
46
67
  width: min-content;
47
68
  }
48
69
 
49
- jinn-toast .jinn-toast.sticky {
70
+ jinn-toast .jinn-toast.sticky,
71
+ jinn-toast .jinn-toast.confirm {
50
72
  pointer-events: auto;
51
73
  }
52
74
 
75
+ jinn-toast .jinn-toast.confirm {
76
+ padding-bottom: 0.75rem;
77
+ }
78
+
79
+ jinn-toast .jinn-toast-body {
80
+ padding-right: 1.25rem;
81
+ }
82
+
83
+ jinn-toast .jinn-toast-actions {
84
+ display: flex;
85
+ justify-content: flex-end;
86
+ gap: 0.5rem;
87
+ margin-top: 0.75rem;
88
+ }
89
+
90
+ jinn-toast .jinn-toast-action {
91
+ border: 1px solid rgba(255, 255, 255, 0.35);
92
+ border-radius: 4px;
93
+ background: rgba(255, 255, 255, 0.12);
94
+ color: inherit;
95
+ cursor: pointer;
96
+ font: inherit;
97
+ font-size: 0.875rem;
98
+ line-height: 1.2;
99
+ padding: 0.35rem 0.75rem;
100
+ }
101
+
102
+ jinn-toast .jinn-toast-action:hover {
103
+ background: rgba(255, 255, 255, 0.22);
104
+ }
105
+
106
+ jinn-toast .jinn-toast-action.primary {
107
+ background: rgba(255, 255, 255, 0.92);
108
+ border-color: transparent;
109
+ color: #1a1816;
110
+ font-weight: 600;
111
+ }
112
+
113
+ jinn-toast .jinn-toast.warn .jinn-toast-action.primary {
114
+ color: #1a1816;
115
+ }
116
+
53
117
  jinn-toast .close-button {
54
118
  position: absolute;
55
119
  top: 4px;
@@ -91,53 +155,91 @@ class l extends HTMLElement {
91
155
  `;
92
156
  }
93
157
  setupEventListeners() {
94
- document.addEventListener("jinn-toast", (t) => {
95
- this.showToast(
96
- t.detail.message,
97
- t.detail.type || "info",
98
- t.detail.nohtml || !1,
99
- t.detail.sticky || !1
100
- );
158
+ document.addEventListener("jinn-toast", (e) => {
159
+ const { message: o, type: i, nohtml: n, sticky: t, confirm: a } = e.detail;
160
+ a ? this.showConfirmToast(o, i || "info", n || !1, a) : this.showToast(o, i || "info", n || !1, t || !1);
101
161
  });
102
162
  }
103
- showToast(t, a, i = !1, e = !1) {
104
- const n = document.createElement("div");
105
- n.className = `jinn-toast ${a} ${e ? "sticky" : ""}`;
106
- const s = () => {
107
- n.classList.remove("show"), setTimeout(() => {
108
- r.removeChild(n);
163
+ /**
164
+ * @param {string|Node|((close: () => void) => Node)} message
165
+ * @param {string} type
166
+ * @param {boolean} nohtml
167
+ * @param {boolean} sticky
168
+ */
169
+ showToast(e, o, i = !1, n = !1) {
170
+ const t = document.createElement("div");
171
+ t.className = `jinn-toast ${o} ${n ? "sticky" : ""}`;
172
+ const a = () => {
173
+ t.classList.remove("show"), setTimeout(() => {
174
+ r.removeChild(t);
109
175
  }, 300);
110
176
  };
111
- if (typeof t == "string")
112
- i ? n.textContent = t : n.innerHTML = t;
113
- else if (t instanceof Node)
114
- n.appendChild(t);
115
- else if (typeof t == "function") {
116
- const o = t(s);
117
- if (o instanceof Node)
118
- n.appendChild(o);
119
- else {
120
- console.warn("Function message did not return a valid Node.");
121
- return;
122
- }
123
- } else {
124
- console.warn("Invalid message type for toast. Expected string, Node, or function.");
125
- return;
126
- }
127
- if (e) {
128
- const o = document.createElement("button");
129
- o.className = "close-button", o.innerHTML = `
177
+ if (this._setToastContent(t, e, i, a), n) {
178
+ const s = document.createElement("button");
179
+ s.className = "close-button", s.innerHTML = `
130
180
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16">
131
181
  <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>
132
182
  </svg>
133
- `, o.addEventListener("click", s), n.appendChild(o);
183
+ `, s.addEventListener("click", a), t.appendChild(s);
134
184
  }
135
185
  const r = this.querySelector(".jinn-toast-container");
136
- r.appendChild(n), n.offsetHeight, n.classList.add("show"), e || setTimeout(s, this.duration);
186
+ r.appendChild(t), t.offsetHeight, t.classList.add("show"), n || setTimeout(a, this.duration);
187
+ }
188
+ /**
189
+ * @param {string|Node|((close: () => void) => Node)} message
190
+ * @param {string} type
191
+ * @param {boolean} nohtml
192
+ * @param {{ confirmLabel?: string, cancelLabel?: string, onConfirm?: () => void, onCancel?: () => void }} confirm
193
+ */
194
+ showConfirmToast(e, o, i, n) {
195
+ const t = document.createElement("div");
196
+ t.className = `jinn-toast confirm ${o}`;
197
+ let a = !1;
198
+ const r = (b) => {
199
+ var j, f;
200
+ a || (a = !0, b ? (j = n.onConfirm) == null || j.call(n) : (f = n.onCancel) == null || f.call(n), s());
201
+ }, s = () => {
202
+ t.classList.remove("show"), setTimeout(() => {
203
+ m.removeChild(t);
204
+ }, 300);
205
+ }, u = document.createElement("div");
206
+ u.className = "jinn-toast-body", this._setToastContent(u, e, i, s), t.appendChild(u);
207
+ const d = document.createElement("div");
208
+ d.className = "jinn-toast-actions";
209
+ const c = document.createElement("button");
210
+ c.type = "button", c.className = "jinn-toast-action", c.textContent = n.cancelLabel || "Cancel", c.addEventListener("click", () => r(!1));
211
+ const l = document.createElement("button");
212
+ l.type = "button", l.className = "jinn-toast-action primary", l.textContent = n.confirmLabel || "OK", l.addEventListener("click", () => r(!0)), d.appendChild(c), d.appendChild(l), t.appendChild(d);
213
+ const p = document.createElement("button");
214
+ p.className = "close-button", p.innerHTML = `
215
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16">
216
+ <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>
217
+ </svg>
218
+ `, p.addEventListener("click", () => r(!1)), t.appendChild(p);
219
+ const m = this.querySelector(".jinn-toast-container");
220
+ m.appendChild(t), t.offsetHeight, t.classList.add("show");
221
+ }
222
+ /**
223
+ * @param {HTMLElement} target
224
+ * @param {string|Node|((close: () => void) => Node)} message
225
+ * @param {boolean} nohtml
226
+ * @param {() => void} closeToast
227
+ */
228
+ _setToastContent(e, o, i, n) {
229
+ if (typeof o == "string")
230
+ i ? e.textContent = o : e.innerHTML = o;
231
+ else if (o instanceof Node)
232
+ e.appendChild(o);
233
+ else if (typeof o == "function") {
234
+ const t = o(n);
235
+ t instanceof Node ? e.appendChild(t) : console.warn("Function message did not return a valid Node.");
236
+ } else
237
+ console.warn("Invalid message type for toast. Expected string, Node, or function.");
137
238
  }
138
239
  }
139
- customElements.get("jinn-toast") || customElements.define("jinn-toast", l);
240
+ customElements.get("jinn-toast") || customElements.define("jinn-toast", v);
140
241
  export {
141
- l as JinnToast
242
+ v as JinnToast,
243
+ g as jinnToastConfirm
142
244
  };
143
245
  //# sourceMappingURL=jinn-toast.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jinn-toast.es.js","sources":["../src/components/jinn-toast.js"],"sourcesContent":["export class JinnToast extends HTMLElement {\n constructor() {\n super();\n this.duration = 3000; // Default duration in milliseconds\n this.stickyDuration = 30000; // Default sticky duration in milliseconds\n }\n\n static get observedAttributes() {\n return ['duration'];\n }\n\n attributeChangedCallback(name, oldValue, newValue) {\n if (name === 'duration') {\n this.duration = parseInt(newValue) || 3000;\n }\n }\n\n connectedCallback() {\n this.render();\n this.setupEventListeners();\n }\n\n render() {\n this.innerHTML = `\n <style>\n jinn-toast .jinn-toast-container {\n position: fixed;\n bottom: 20px;\n right: 20px;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n z-index: var(--jinn-toast-z-index, 1000);\n }\n\n jinn-toast .jinn-toast {\n padding: 12px 24px;\n margin: 8px 0;\n border-radius: 4px;\n color: var(--jinn-toast-color, #F0F0F0);\n opacity: 0;\n transform: translateY(20px);\n transition: opacity 0.3s, transform 0.3s;\n max-width: var(--jinn-toast-max-width, 30vw);\n word-wrap: break-word;\n pointer-events: none;\n position: relative;\n }\n\n jinn-toast .jinn-toast p {\n color: var(--jinn-toast-color, #F0F0F0);\n }\n\n jinn-toast .jinn-toast input {\n width: min-content;\n }\n\n jinn-toast .jinn-toast.sticky {\n pointer-events: auto;\n }\n\n jinn-toast .close-button {\n position: absolute;\n top: 4px;\n right: 4px;\n background: none;\n border: none;\n color: inherit;\n cursor: pointer;\n font-size: 16px;\n line-height: 1;\n padding: 4px;\n opacity: 0.7;\n transition: opacity 0.2s;\n }\n\n jinn-toast .close-button:hover {\n opacity: 1;\n }\n\n jinn-toast .jinn-toast.show {\n opacity: 1;\n transform: translateY(0);\n }\n\n jinn-toast .jinn-toast.error {\n background-color: var(--jinn-toast-error-color, #EE402E);\n }\n\n jinn-toast .jinn-toast.warn {\n background-color: var(--jinn-toast-warn-color, #FF9500);\n color: #000;\n }\n\n jinn-toast .jinn-toast.info {\n background-color: var(--jinn-toast-info-color, #33790F);\n }\n </style>\n <div class=\"jinn-toast-container\"></div>\n `;\n }\n\n setupEventListeners() {\n document.addEventListener('jinn-toast', (event) => {\n this.showToast(\n event.detail.message,\n event.detail.type || 'info',\n event.detail.nohtml || false,\n event.detail.sticky || false,\n );\n });\n }\n\n showToast(message, type, nohtml = false, sticky = false) {\n const toast = document.createElement('div');\n toast.className = `jinn-toast ${type} ${sticky ? 'sticky' : ''}`;\n\n const closeToast = () => {\n toast.classList.remove('show');\n setTimeout(() => {\n container.removeChild(toast);\n }, 300);\n };\n\n if (typeof message === 'string') {\n if (nohtml) {\n toast.textContent = message;\n } else {\n toast.innerHTML = message;\n }\n } else if (message instanceof Node) {\n toast.appendChild(message);\n } else if (typeof message === 'function') {\n const content = message(closeToast);\n if (content instanceof Node) {\n toast.appendChild(content);\n } else {\n console.warn('Function message did not return a valid Node.');\n return;\n }\n } else {\n console.warn('Invalid message type for toast. Expected string, Node, or function.');\n return;\n }\n\n if (sticky) {\n const closeButton = document.createElement('button');\n closeButton.className = 'close-button';\n closeButton.innerHTML = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-x\" viewBox=\"0 0 16 16\">\n <path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708\"/>\n </svg>\n `;\n closeButton.addEventListener('click', closeToast);\n toast.appendChild(closeButton);\n }\n\n const container = this.querySelector('.jinn-toast-container');\n container.appendChild(toast);\n\n // Trigger reflow to enable animation\n toast.offsetHeight;\n toast.classList.add('show');\n\n if (!sticky) {\n setTimeout(closeToast, this.duration);\n }\n }\n}\n\nif (!customElements.get('jinn-toast')) {\n customElements.define('jinn-toast', JinnToast);\n}\n"],"names":["JinnToast","name","oldValue","newValue","event","message","type","nohtml","sticky","toast","closeToast","container","content","closeButton"],"mappings":"AAAO,MAAMA,UAAkB,YAAY;AAAA,EACvC,cAAc;AACV,UAAK,GACL,KAAK,WAAW,KAChB,KAAK,iBAAiB;AAAA,EAC1B;AAAA,EAEA,WAAW,qBAAqB;AAC5B,WAAO,CAAC,UAAU;AAAA,EACtB;AAAA,EAEA,yBAAyBC,GAAMC,GAAUC,GAAU;AAC/C,IAAIF,MAAS,eACT,KAAK,WAAW,SAASE,CAAQ,KAAK;AAAA,EAE9C;AAAA,EAEA,oBAAoB;AAChB,SAAK,OAAM,GACX,KAAK,oBAAmB;AAAA,EAC5B;AAAA,EAEA,SAAS;AACL,SAAK,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6ErB;AAAA,EAEA,sBAAsB;AAClB,aAAS,iBAAiB,cAAc,CAACC,MAAU;AAC/C,WAAK;AAAA,QACDA,EAAM,OAAO;AAAA,QACbA,EAAM,OAAO,QAAQ;AAAA,QACrBA,EAAM,OAAO,UAAU;AAAA,QACvBA,EAAM,OAAO,UAAU;AAAA,MACvC;AAAA,IACQ,CAAC;AAAA,EACL;AAAA,EAEA,UAAUC,GAASC,GAAMC,IAAS,IAAOC,IAAS,IAAO;AACrD,UAAMC,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY,cAAcH,CAAI,IAAIE,IAAS,WAAW,EAAE;AAE9D,UAAME,IAAa,MAAM;AACrB,MAAAD,EAAM,UAAU,OAAO,MAAM,GAC7B,WAAW,MAAM;AACb,QAAAE,EAAU,YAAYF,CAAK;AAAA,MAC/B,GAAG,GAAG;AAAA,IACV;AAEA,QAAI,OAAOJ,KAAY;AACnB,MAAIE,IACAE,EAAM,cAAcJ,IAEpBI,EAAM,YAAYJ;AAAA,aAEfA,aAAmB;AAC1B,MAAAI,EAAM,YAAYJ,CAAO;AAAA,aAClB,OAAOA,KAAY,YAAY;AACtC,YAAMO,IAAUP,EAAQK,CAAU;AAClC,UAAIE,aAAmB;AACnB,QAAAH,EAAM,YAAYG,CAAO;AAAA,WACtB;AACH,gBAAQ,KAAK,+CAA+C;AAC5D;AAAA,MACJ;AAAA,IACJ,OAAO;AACH,cAAQ,KAAK,qEAAqE;AAClF;AAAA,IACJ;AAEA,QAAIJ,GAAQ;AACR,YAAMK,IAAc,SAAS,cAAc,QAAQ;AACnD,MAAAA,EAAY,YAAY,gBACxBA,EAAY,YAAY;AAAA;AAAA;AAAA;AAAA,eAKxBA,EAAY,iBAAiB,SAASH,CAAU,GAChDD,EAAM,YAAYI,CAAW;AAAA,IACjC;AAEA,UAAMF,IAAY,KAAK,cAAc,uBAAuB;AAC5D,IAAAA,EAAU,YAAYF,CAAK,GAG3BA,EAAM,cACNA,EAAM,UAAU,IAAI,MAAM,GAErBD,KACD,WAAWE,GAAY,KAAK,QAAQ;AAAA,EAE5C;AACJ;AAEK,eAAe,IAAI,YAAY,KAChC,eAAe,OAAO,cAAcV,CAAS;"}
1
+ {"version":3,"file":"jinn-toast.es.js","sources":["../src/components/jinn-toast.js"],"sourcesContent":["/**\n * Show a sticky toast with confirm/cancel actions.\n *\n * @param {string|Node|((close: () => void) => Node)} message\n * @param {object} [options]\n * @param {string} [options.confirmLabel='OK']\n * @param {string} [options.cancelLabel='Cancel']\n * @param {string} [options.type='info']\n * @param {boolean} [options.nohtml=false]\n * @returns {Promise<boolean>} Resolves to `true` on confirm, `false` on cancel/close\n */\nexport function jinnToastConfirm(message, options = {}) {\n const { confirmLabel = 'OK', cancelLabel = 'Cancel', type = 'info', nohtml = false } = options;\n\n return new Promise((resolve) => {\n document.dispatchEvent(\n new CustomEvent('jinn-toast', {\n detail: {\n message,\n type,\n nohtml,\n sticky: true,\n confirm: {\n confirmLabel,\n cancelLabel,\n onConfirm: () => resolve(true),\n onCancel: () => resolve(false),\n },\n },\n }),\n );\n });\n}\n\nexport class JinnToast extends HTMLElement {\n constructor() {\n super();\n this.duration = 3000; // Default duration in milliseconds\n this.stickyDuration = 30000; // Default sticky duration in milliseconds\n }\n\n static get observedAttributes() {\n return ['duration'];\n }\n\n attributeChangedCallback(name, oldValue, newValue) {\n if (name === 'duration') {\n this.duration = parseInt(newValue) || 3000;\n }\n }\n\n connectedCallback() {\n this.render();\n this.setupEventListeners();\n }\n\n render() {\n this.innerHTML = `\n <style>\n jinn-toast .jinn-toast-container {\n position: fixed;\n bottom: 20px;\n right: 20px;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n z-index: var(--jinn-toast-z-index, 1000);\n }\n\n jinn-toast .jinn-toast {\n padding: 12px 24px;\n margin: 8px 0;\n border-radius: 4px;\n color: var(--jinn-toast-color, #F0F0F0);\n opacity: 0;\n transform: translateY(20px);\n transition: opacity 0.3s, transform 0.3s;\n max-width: var(--jinn-toast-max-width, 30vw);\n word-wrap: break-word;\n pointer-events: none;\n position: relative;\n }\n\n jinn-toast .jinn-toast p {\n color: var(--jinn-toast-color, #F0F0F0);\n }\n\n jinn-toast .jinn-toast input {\n width: min-content;\n }\n\n jinn-toast .jinn-toast.sticky,\n jinn-toast .jinn-toast.confirm {\n pointer-events: auto;\n }\n\n jinn-toast .jinn-toast.confirm {\n padding-bottom: 0.75rem;\n }\n\n jinn-toast .jinn-toast-body {\n padding-right: 1.25rem;\n }\n\n jinn-toast .jinn-toast-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n margin-top: 0.75rem;\n }\n\n jinn-toast .jinn-toast-action {\n border: 1px solid rgba(255, 255, 255, 0.35);\n border-radius: 4px;\n background: rgba(255, 255, 255, 0.12);\n color: inherit;\n cursor: pointer;\n font: inherit;\n font-size: 0.875rem;\n line-height: 1.2;\n padding: 0.35rem 0.75rem;\n }\n\n jinn-toast .jinn-toast-action:hover {\n background: rgba(255, 255, 255, 0.22);\n }\n\n jinn-toast .jinn-toast-action.primary {\n background: rgba(255, 255, 255, 0.92);\n border-color: transparent;\n color: #1a1816;\n font-weight: 600;\n }\n\n jinn-toast .jinn-toast.warn .jinn-toast-action.primary {\n color: #1a1816;\n }\n\n jinn-toast .close-button {\n position: absolute;\n top: 4px;\n right: 4px;\n background: none;\n border: none;\n color: inherit;\n cursor: pointer;\n font-size: 16px;\n line-height: 1;\n padding: 4px;\n opacity: 0.7;\n transition: opacity 0.2s;\n }\n\n jinn-toast .close-button:hover {\n opacity: 1;\n }\n\n jinn-toast .jinn-toast.show {\n opacity: 1;\n transform: translateY(0);\n }\n\n jinn-toast .jinn-toast.error {\n background-color: var(--jinn-toast-error-color, #EE402E);\n }\n\n jinn-toast .jinn-toast.warn {\n background-color: var(--jinn-toast-warn-color, #FF9500);\n color: #000;\n }\n\n jinn-toast .jinn-toast.info {\n background-color: var(--jinn-toast-info-color, #33790F);\n }\n </style>\n <div class=\"jinn-toast-container\"></div>\n `;\n }\n\n setupEventListeners() {\n document.addEventListener('jinn-toast', (event) => {\n const { message, type, nohtml, sticky, confirm } = event.detail;\n if (confirm) {\n this.showConfirmToast(message, type || 'info', nohtml || false, confirm);\n } else {\n this.showToast(message, type || 'info', nohtml || false, sticky || false);\n }\n });\n }\n\n /**\n * @param {string|Node|((close: () => void) => Node)} message\n * @param {string} type\n * @param {boolean} nohtml\n * @param {boolean} sticky\n */\n showToast(message, type, nohtml = false, sticky = false) {\n const toast = document.createElement('div');\n toast.className = `jinn-toast ${type} ${sticky ? 'sticky' : ''}`;\n\n const closeToast = () => {\n toast.classList.remove('show');\n setTimeout(() => {\n container.removeChild(toast);\n }, 300);\n };\n\n this._setToastContent(toast, message, nohtml, closeToast);\n\n if (sticky) {\n const closeButton = document.createElement('button');\n closeButton.className = 'close-button';\n closeButton.innerHTML = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-x\" viewBox=\"0 0 16 16\">\n <path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708\"/>\n </svg>\n `;\n closeButton.addEventListener('click', closeToast);\n toast.appendChild(closeButton);\n }\n\n const container = this.querySelector('.jinn-toast-container');\n container.appendChild(toast);\n\n // Trigger reflow to enable animation\n toast.offsetHeight;\n toast.classList.add('show');\n\n if (!sticky) {\n setTimeout(closeToast, this.duration);\n }\n }\n\n /**\n * @param {string|Node|((close: () => void) => Node)} message\n * @param {string} type\n * @param {boolean} nohtml\n * @param {{ confirmLabel?: string, cancelLabel?: string, onConfirm?: () => void, onCancel?: () => void }} confirm\n */\n showConfirmToast(message, type, nohtml, confirm) {\n const toast = document.createElement('div');\n toast.className = `jinn-toast confirm ${type}`;\n\n let settled = false;\n const settle = (confirmed) => {\n if (settled) {\n return;\n }\n settled = true;\n if (confirmed) {\n confirm.onConfirm?.();\n } else {\n confirm.onCancel?.();\n }\n closeToast();\n };\n\n const closeToast = () => {\n toast.classList.remove('show');\n setTimeout(() => {\n container.removeChild(toast);\n }, 300);\n };\n\n const body = document.createElement('div');\n body.className = 'jinn-toast-body';\n this._setToastContent(body, message, nohtml, closeToast);\n toast.appendChild(body);\n\n const actions = document.createElement('div');\n actions.className = 'jinn-toast-actions';\n\n const cancelButton = document.createElement('button');\n cancelButton.type = 'button';\n cancelButton.className = 'jinn-toast-action';\n cancelButton.textContent = confirm.cancelLabel || 'Cancel';\n cancelButton.addEventListener('click', () => settle(false));\n\n const confirmButton = document.createElement('button');\n confirmButton.type = 'button';\n confirmButton.className = 'jinn-toast-action primary';\n confirmButton.textContent = confirm.confirmLabel || 'OK';\n confirmButton.addEventListener('click', () => settle(true));\n\n actions.appendChild(cancelButton);\n actions.appendChild(confirmButton);\n toast.appendChild(actions);\n\n const closeButton = document.createElement('button');\n closeButton.className = 'close-button';\n closeButton.innerHTML = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-x\" viewBox=\"0 0 16 16\">\n <path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708\"/>\n </svg>\n `;\n closeButton.addEventListener('click', () => settle(false));\n toast.appendChild(closeButton);\n\n const container = this.querySelector('.jinn-toast-container');\n container.appendChild(toast);\n\n toast.offsetHeight;\n toast.classList.add('show');\n }\n\n /**\n * @param {HTMLElement} target\n * @param {string|Node|((close: () => void) => Node)} message\n * @param {boolean} nohtml\n * @param {() => void} closeToast\n */\n _setToastContent(target, message, nohtml, closeToast) {\n if (typeof message === 'string') {\n if (nohtml) {\n target.textContent = message;\n } else {\n target.innerHTML = message;\n }\n } else if (message instanceof Node) {\n target.appendChild(message);\n } else if (typeof message === 'function') {\n const content = message(closeToast);\n if (content instanceof Node) {\n target.appendChild(content);\n } else {\n console.warn('Function message did not return a valid Node.');\n }\n } else {\n console.warn('Invalid message type for toast. Expected string, Node, or function.');\n }\n }\n}\n\nif (!customElements.get('jinn-toast')) {\n customElements.define('jinn-toast', JinnToast);\n}\n"],"names":["jinnToastConfirm","message","options","confirmLabel","cancelLabel","type","nohtml","resolve","JinnToast","name","oldValue","newValue","event","sticky","confirm","toast","closeToast","container","closeButton","settled","settle","confirmed","_a","_b","body","actions","cancelButton","confirmButton","target","content"],"mappings":"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"}
@@ -0,0 +1,261 @@
1
+ const C = "jinntap";
2
+ const D = "documents";
3
+ class O {
4
+ /**
5
+ * @param {string} [dbName]
6
+ */
7
+ constructor(n = C) {
8
+ this.dbName = n, this._db = null;
9
+ }
10
+ /**
11
+ * Open (or create) the database.
12
+ * @returns {Promise<DocumentStore>}
13
+ */
14
+ async open() {
15
+ return this._db ? this : (this._db = await new Promise((n, a) => {
16
+ const s = indexedDB.open(this.dbName, 1);
17
+ s.onerror = () => a(s.error ?? new Error("Failed to open IndexedDB")), s.onsuccess = () => n(s.result), s.onupgradeneeded = (c) => {
18
+ const u = (
19
+ /** @type {IDBOpenDBRequest} */
20
+ c.target.result
21
+ );
22
+ if (!u.objectStoreNames.contains(D)) {
23
+ const l = u.createObjectStore(D, { keyPath: "id" });
24
+ l.createIndex("updatedAt", "updatedAt", { unique: !1 }), l.createIndex("format", "format", { unique: !1 });
25
+ }
26
+ };
27
+ }), this);
28
+ }
29
+ /**
30
+ * @returns {IDBDatabase}
31
+ */
32
+ _requireDb() {
33
+ if (!this._db)
34
+ throw new Error("DocumentStore is not open; call open() first");
35
+ return this._db;
36
+ }
37
+ /**
38
+ * @param {IDBTransactionMode} mode
39
+ * @returns {IDBObjectStore}
40
+ */
41
+ _store(n) {
42
+ return this._requireDb().transaction(D, n).objectStore(D);
43
+ }
44
+ /**
45
+ * @template T
46
+ * @param {IDBRequest<T>} request
47
+ * @returns {Promise<T>}
48
+ */
49
+ _request(n) {
50
+ return new Promise((a, s) => {
51
+ n.onsuccess = () => a(n.result), n.onerror = () => s(n.error ?? new Error("IndexedDB request failed"));
52
+ });
53
+ }
54
+ /**
55
+ * @param {string} id
56
+ * @returns {Promise<StoredDocument|undefined>}
57
+ */
58
+ async get(n) {
59
+ return await this._request(this._store("readonly").get(n)) ?? void 0;
60
+ }
61
+ /**
62
+ * @returns {Promise<StoredDocument[]>}
63
+ */
64
+ async list() {
65
+ return (await this._request(this._store("readonly").getAll()) ?? []).sort((a, s) => (s.updatedAt ?? 0) - (a.updatedAt ?? 0));
66
+ }
67
+ /**
68
+ * Insert or replace a document record.
69
+ * @param {StoredDocument} doc
70
+ * @returns {Promise<StoredDocument>}
71
+ */
72
+ async put(n) {
73
+ if (!(n != null && n.id))
74
+ throw new Error("DocumentStore.put requires a document with an id");
75
+ const a = {
76
+ ...n,
77
+ updatedAt: n.updatedAt ?? Date.now()
78
+ };
79
+ return await this._request(this._store("readwrite").put(a)), a;
80
+ }
81
+ /**
82
+ * @param {string} id
83
+ * @returns {Promise<void>}
84
+ */
85
+ async delete(n) {
86
+ await this._request(this._store("readwrite").delete(n));
87
+ }
88
+ /**
89
+ * Close the database connection.
90
+ */
91
+ close() {
92
+ this._db && (this._db.close(), this._db = null);
93
+ }
94
+ }
95
+ const U = /* @__PURE__ */ new Set(["untitled document", "untitled article", "untitled"]);
96
+ function T(t) {
97
+ return !t || U.has(t.trim().toLowerCase());
98
+ }
99
+ function S(t, n = 80) {
100
+ const a = t.replace(/\s+/g, " ").trim();
101
+ return a.length <= n ? a : `${a.slice(0, n - 1).trimEnd()}…`;
102
+ }
103
+ function j(t) {
104
+ var n, a;
105
+ if (!t || typeof t != "string")
106
+ return null;
107
+ try {
108
+ const s = new DOMParser().parseFromString(t, "application/xml");
109
+ if (s.querySelector("parsererror"))
110
+ return null;
111
+ const c = s.getElementsByTagName("*");
112
+ let u = null, l = null, i = null;
113
+ for (const o of c) {
114
+ const m = o.localName;
115
+ if (m === "title" && ((n = o.parentElement) == null ? void 0 : n.localName) === "titleStmt") {
116
+ u = o;
117
+ break;
118
+ }
119
+ m === "article-title" && !l && (l = o), m === "title" && !i && (i = o);
120
+ }
121
+ const f = u || l || i, d = (a = f == null ? void 0 : f.textContent) == null ? void 0 : a.trim();
122
+ return d && !T(d) ? S(d) : null;
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+ function k({ xml: t, metadata: n, plainText: a, fallback: s = "Untitled Document" } = {}) {
128
+ var i;
129
+ const c = (i = n == null ? void 0 : n.title) == null ? void 0 : i.trim();
130
+ if (c && !T(c))
131
+ return S(c);
132
+ const u = j(t);
133
+ if (u)
134
+ return u;
135
+ const l = a == null ? void 0 : a.trim().split(/\r?\n/).find((f) => f.trim());
136
+ return l ? S(l) : s;
137
+ }
138
+ async function M(t, n = {}) {
139
+ const { debounceMs: a = 500, force: s = !1, autoRestore: c = !1, onDraftAvailable: u, onNameChange: l, onRestore: i } = n;
140
+ if (!s && t.hasAttribute("server"))
141
+ return null;
142
+ const f = (t.getAttribute("format") || t.format || "tei").toLowerCase(), d = n.documentId || `current-${f}`, o = n.store || new O();
143
+ await o.open();
144
+ let m = !1, g = "Untitled Document", p = null, E = !1, A = !1, y = !1, _;
145
+ const b = (e) => {
146
+ g = e, l == null || l(e);
147
+ }, N = (e, r = {}) => {
148
+ var q;
149
+ const h = t.metadata || {};
150
+ let w = g;
151
+ return m || (w = k({
152
+ xml: e,
153
+ metadata: h,
154
+ plainText: typeof t.content == "string" ? t.content : void 0
155
+ }), !T(w) && h.title !== w && (t.metadata = { ...h, title: w })), b(w), {
156
+ id: d,
157
+ name: w,
158
+ format: f,
159
+ xml: e,
160
+ updatedAt: Date.now(),
161
+ nameLocked: m,
162
+ filename: (q = t.metadata) == null ? void 0 : q.name,
163
+ ...r
164
+ };
165
+ }, L = async (e) => {
166
+ if (E || y || !e)
167
+ return;
168
+ const r = N(e);
169
+ return await o.put(r), r;
170
+ }, I = (e) => {
171
+ E || y || (clearTimeout(p), p = setTimeout(() => {
172
+ L(e).catch((r) => console.error("jinntap local store save failed", r));
173
+ }, a));
174
+ }, R = (e) => {
175
+ var r;
176
+ I((r = e.detail) == null ? void 0 : r.xml);
177
+ }, v = async (e) => {
178
+ var r;
179
+ if (!(e != null && e.xml))
180
+ return !1;
181
+ y = !0;
182
+ try {
183
+ t.hasAttribute("url") && t.removeAttribute("url"), t.xml = e.xml, m = !!e.nameLocked;
184
+ const h = e.filename || ((r = t.metadata) == null ? void 0 : r.name) || "untitled.xml";
185
+ return t.metadata = {
186
+ ...t.metadata || {},
187
+ title: e.name,
188
+ name: h
189
+ }, b(e.name), A = !0, _ = void 0, i == null || i(e), !0;
190
+ } finally {
191
+ setTimeout(() => {
192
+ y = !1;
193
+ }, a + 50);
194
+ }
195
+ }, B = async () => {
196
+ const e = await o.get(d);
197
+ if (!(e != null && e.xml))
198
+ return !1;
199
+ _ = e;
200
+ let r = c;
201
+ return !c && u && (r = !!await u(e)), r ? v(e) : !1;
202
+ };
203
+ return await new Promise((e) => {
204
+ if (t._initialized || t.editor) {
205
+ e();
206
+ return;
207
+ }
208
+ const r = () => e();
209
+ t.addEventListener("ready", r, { once: !0 }), (t._initialized || t.editor) && (t.removeEventListener("ready", r), e());
210
+ }), await B(), t.addEventListener("content-change", R), {
211
+ store: o,
212
+ documentId: d,
213
+ get restored() {
214
+ return A;
215
+ },
216
+ get pendingDraft() {
217
+ return _;
218
+ },
219
+ detach() {
220
+ E = !0, clearTimeout(p), t.removeEventListener("content-change", R);
221
+ },
222
+ async restore(e) {
223
+ const r = e || _ || await o.get(d);
224
+ return v(r);
225
+ },
226
+ async rename(e) {
227
+ const r = e == null ? void 0 : e.trim();
228
+ if (!r)
229
+ throw new Error("Document name must not be empty");
230
+ m = !0, b(r), t.metadata = {
231
+ ...t.metadata || {},
232
+ title: r
233
+ };
234
+ const h = t.xml;
235
+ return o.put(
236
+ N(h, {
237
+ name: r,
238
+ nameLocked: !0
239
+ })
240
+ );
241
+ },
242
+ async clear() {
243
+ clearTimeout(p), await o.delete(d), m = !1, b("Untitled Document");
244
+ },
245
+ async getRecord() {
246
+ return o.get(d);
247
+ },
248
+ async saveNow() {
249
+ return clearTimeout(p), L(t.xml);
250
+ }
251
+ };
252
+ }
253
+ export {
254
+ O as DocumentStore,
255
+ M as attachLocalStore,
256
+ k as deduceDocumentName,
257
+ j as extractTitleFromXml,
258
+ T as isGenericTitle,
259
+ S as truncateTitle
260
+ };
261
+ //# sourceMappingURL=storage.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.es.js","sources":["../src/storage/document-store.js","../src/storage/document-name.js","../src/storage/attach-local-store.js"],"sourcesContent":["const DB_NAME = 'jinntap';\nconst DB_VERSION = 1;\nconst DOCUMENTS_STORE = 'documents';\n\n/**\n * @typedef {object} StoredDocument\n * @property {string} id\n * @property {string} name - Human-readable display title\n * @property {string} format - `'tei'` | `'jats'`\n * @property {string} xml - Full document XML\n * @property {number} updatedAt - Epoch ms\n * @property {boolean} [nameLocked] - When true, autosave will not overwrite `name`\n * @property {string} [filename] - Optional download filename (`metadata.name`)\n */\n\n/**\n * Thin IndexedDB wrapper for local JinnTap documents.\n * Schema versioning leaves room for a future `assets` object store.\n */\nexport class DocumentStore {\n /**\n * @param {string} [dbName]\n */\n constructor(dbName = DB_NAME) {\n this.dbName = dbName;\n /** @type {IDBDatabase|null} */\n this._db = null;\n }\n\n /**\n * Open (or create) the database.\n * @returns {Promise<DocumentStore>}\n */\n async open() {\n if (this._db) {\n return this;\n }\n this._db = await new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, DB_VERSION);\n request.onerror = () => reject(request.error ?? new Error('Failed to open IndexedDB'));\n request.onsuccess = () => resolve(request.result);\n request.onupgradeneeded = (event) => {\n const db = /** @type {IDBOpenDBRequest} */ (event.target).result;\n if (!db.objectStoreNames.contains(DOCUMENTS_STORE)) {\n const store = db.createObjectStore(DOCUMENTS_STORE, { keyPath: 'id' });\n store.createIndex('updatedAt', 'updatedAt', { unique: false });\n store.createIndex('format', 'format', { unique: false });\n }\n // Future: assets object store in a later DB_VERSION\n };\n });\n return this;\n }\n\n /**\n * @returns {IDBDatabase}\n */\n _requireDb() {\n if (!this._db) {\n throw new Error('DocumentStore is not open; call open() first');\n }\n return this._db;\n }\n\n /**\n * @param {IDBTransactionMode} mode\n * @returns {IDBObjectStore}\n */\n _store(mode) {\n return this._requireDb().transaction(DOCUMENTS_STORE, mode).objectStore(DOCUMENTS_STORE);\n }\n\n /**\n * @template T\n * @param {IDBRequest<T>} request\n * @returns {Promise<T>}\n */\n _request(request) {\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error('IndexedDB request failed'));\n });\n }\n\n /**\n * @param {string} id\n * @returns {Promise<StoredDocument|undefined>}\n */\n async get(id) {\n const result = await this._request(this._store('readonly').get(id));\n return result ?? undefined;\n }\n\n /**\n * @returns {Promise<StoredDocument[]>}\n */\n async list() {\n const docs = await this._request(this._store('readonly').getAll());\n return (docs ?? []).sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));\n }\n\n /**\n * Insert or replace a document record.\n * @param {StoredDocument} doc\n * @returns {Promise<StoredDocument>}\n */\n async put(doc) {\n if (!doc?.id) {\n throw new Error('DocumentStore.put requires a document with an id');\n }\n /** @type {StoredDocument} */\n const record = {\n ...doc,\n updatedAt: doc.updatedAt ?? Date.now(),\n };\n await this._request(this._store('readwrite').put(record));\n return record;\n }\n\n /**\n * @param {string} id\n * @returns {Promise<void>}\n */\n async delete(id) {\n await this._request(this._store('readwrite').delete(id));\n }\n\n /**\n * Close the database connection.\n */\n close() {\n if (this._db) {\n this._db.close();\n this._db = null;\n }\n }\n}\n","const GENERIC_TITLES = new Set(['untitled document', 'untitled article', 'untitled']);\n\n/**\n * @param {string} title\n * @returns {boolean}\n */\nexport function isGenericTitle(title) {\n return !title || GENERIC_TITLES.has(title.trim().toLowerCase());\n}\n\n/**\n * @param {string} text\n * @param {number} [max=80]\n * @returns {string}\n */\nexport function truncateTitle(text, max = 80) {\n const cleaned = text.replace(/\\s+/g, ' ').trim();\n if (cleaned.length <= max) {\n return cleaned;\n }\n return `${cleaned.slice(0, max - 1).trimEnd()}…`;\n}\n\n/**\n * Pull a document title from TEI `titleStmt/title` or JATS `article-title`.\n * @param {string} xml\n * @returns {string|null}\n */\nexport function extractTitleFromXml(xml) {\n if (!xml || typeof xml !== 'string') {\n return null;\n }\n try {\n const doc = new DOMParser().parseFromString(xml, 'application/xml');\n if (doc.querySelector('parsererror')) {\n return null;\n }\n\n const elements = doc.getElementsByTagName('*');\n /** @type {Element|null} */\n let titleStmtTitle = null;\n /** @type {Element|null} */\n let articleTitle = null;\n /** @type {Element|null} */\n let anyTitle = null;\n\n for (const el of elements) {\n const name = el.localName;\n if (name === 'title' && el.parentElement?.localName === 'titleStmt') {\n titleStmtTitle = el;\n break;\n }\n if (name === 'article-title' && !articleTitle) {\n articleTitle = el;\n }\n if (name === 'title' && !anyTitle) {\n anyTitle = el;\n }\n }\n\n const node = titleStmtTitle || articleTitle || anyTitle;\n const text = node?.textContent?.trim();\n return text && !isGenericTitle(text) ? truncateTitle(text) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Deduce a display name for a document.\n *\n * Order: meaningful `metadata.title` → XML header title → first plain-text line → fallback.\n *\n * @param {object} options\n * @param {string} [options.xml]\n * @param {{ title?: string }} [options.metadata]\n * @param {string} [options.plainText]\n * @param {string} [options.fallback='Untitled Document']\n * @returns {string}\n */\nexport function deduceDocumentName({ xml, metadata, plainText, fallback = 'Untitled Document' } = {}) {\n const metaTitle = metadata?.title?.trim();\n if (metaTitle && !isGenericTitle(metaTitle)) {\n return truncateTitle(metaTitle);\n }\n\n const fromXml = extractTitleFromXml(xml);\n if (fromXml) {\n return fromXml;\n }\n\n const firstLine = plainText\n ?.trim()\n .split(/\\r?\\n/)\n .find((line) => line.trim());\n if (firstLine) {\n return truncateTitle(firstLine);\n }\n\n return fallback;\n}\n","import { DocumentStore } from './document-store.js';\nimport { deduceDocumentName, isGenericTitle } from './document-name.js';\n\n/**\n * @typedef {import('./document-store.js').StoredDocument} StoredDocument\n */\n\n/**\n * @typedef {object} AttachLocalStoreOptions\n * @property {string} [documentId] - Stable key for the active document (default: `current-<format>`)\n * @property {number} [debounceMs=500]\n * @property {DocumentStore} [store] - Reuse an existing store instance\n * @property {boolean} [force=false] - Attach even when collaboration (`server`) is active\n * @property {boolean} [autoRestore=false] - Restore immediately without asking\n * @property {(record: StoredDocument) => boolean|Promise<boolean>} [onDraftAvailable] - Called when a draft exists; return true to restore\n * @property {(name: string) => void} [onNameChange] - Called when the display name changes\n * @property {(record: StoredDocument) => void} [onRestore] - Called after a draft is restored\n */\n\n/**\n * @typedef {object} LocalStoreHandle\n * @property {DocumentStore} store\n * @property {string} documentId\n * @property {boolean} restored\n * @property {StoredDocument|undefined} pendingDraft\n * @property {() => void} detach\n * @property {(record?: StoredDocument) => Promise<boolean>} restore\n * @property {(name: string) => Promise<StoredDocument>} rename\n * @property {() => Promise<void>} clear\n * @property {() => Promise<StoredDocument|undefined>} getRecord\n * @property {() => Promise<StoredDocument>} saveNow\n */\n\n/**\n * Bind a `<jinn-tap>` editor to IndexedDB: optionally restore a local draft on ready,\n * and debounced-autosave on `content-change`.\n *\n * @param {HTMLElement & { xml: string, metadata: object, format?: string, newDocument?: Function }} editor\n * @param {AttachLocalStoreOptions} [options]\n * @returns {Promise<LocalStoreHandle|null>} `null` when skipped (e.g. collaboration without `force`)\n */\nexport async function attachLocalStore(editor, options = {}) {\n const { debounceMs = 500, force = false, autoRestore = false, onDraftAvailable, onNameChange, onRestore } = options;\n\n if (!force && editor.hasAttribute('server')) {\n return null;\n }\n\n const format = (editor.getAttribute('format') || editor.format || 'tei').toLowerCase();\n const documentId = options.documentId || `current-${format}`;\n const store = options.store || new DocumentStore();\n await store.open();\n\n let nameLocked = false;\n let currentName = 'Untitled Document';\n let timer = null;\n let detached = false;\n let restored = false;\n let suppressingSave = false;\n /** @type {StoredDocument|undefined} */\n let pendingDraft;\n\n const emitName = (name) => {\n currentName = name;\n onNameChange?.(name);\n };\n\n const buildRecord = (xml, overrides = {}) => {\n const metadata = editor.metadata || {};\n let name = currentName;\n if (!nameLocked) {\n name = deduceDocumentName({\n xml,\n metadata,\n plainText: typeof editor.content === 'string' ? editor.content : undefined,\n });\n if (!isGenericTitle(name) && metadata.title !== name) {\n editor.metadata = { ...metadata, title: name };\n }\n }\n emitName(name);\n /** @type {StoredDocument} */\n return {\n id: documentId,\n name,\n format,\n xml,\n updatedAt: Date.now(),\n nameLocked,\n filename: editor.metadata?.name,\n ...overrides,\n };\n };\n\n const persist = async (xml) => {\n if (detached || suppressingSave || !xml) {\n return;\n }\n const record = buildRecord(xml);\n await store.put(record);\n return record;\n };\n\n const scheduleSave = (xml) => {\n if (detached || suppressingSave) {\n return;\n }\n clearTimeout(timer);\n timer = setTimeout(() => {\n persist(xml).catch((err) => console.error('jinntap local store save failed', err));\n }, debounceMs);\n };\n\n const onContentChange = (event) => {\n scheduleSave(event.detail?.xml);\n };\n\n const applyRestore = async (existing) => {\n if (!existing?.xml) {\n return false;\n }\n suppressingSave = true;\n try {\n // Avoid a later url attribute change reloading remote content over the draft\n if (editor.hasAttribute('url')) {\n editor.removeAttribute('url');\n }\n editor.xml = existing.xml;\n nameLocked = Boolean(existing.nameLocked);\n const filename = existing.filename || editor.metadata?.name || 'untitled.xml';\n editor.metadata = {\n ...(editor.metadata || {}),\n title: existing.name,\n name: filename,\n };\n emitName(existing.name);\n restored = true;\n pendingDraft = undefined;\n onRestore?.(existing);\n return true;\n } finally {\n // Allow the restore-triggered content-change to settle before saving again\n setTimeout(() => {\n suppressingSave = false;\n }, debounceMs + 50);\n }\n };\n\n const offerRestore = async () => {\n const existing = await store.get(documentId);\n if (!existing?.xml) {\n return false;\n }\n pendingDraft = existing;\n\n let shouldRestore = autoRestore;\n if (!autoRestore && onDraftAvailable) {\n shouldRestore = Boolean(await onDraftAvailable(existing));\n }\n\n if (shouldRestore) {\n return applyRestore(existing);\n }\n return false;\n };\n\n const waitUntilReady = () =>\n new Promise((resolve) => {\n if (editor._initialized || editor.editor) {\n resolve();\n return;\n }\n const onReady = () => resolve();\n editor.addEventListener('ready', onReady, { once: true });\n // Re-check in case `ready` fired between the guard and the listener\n if (editor._initialized || editor.editor) {\n editor.removeEventListener('ready', onReady);\n resolve();\n }\n });\n\n await waitUntilReady();\n await offerRestore();\n\n editor.addEventListener('content-change', onContentChange);\n\n return {\n store,\n documentId,\n get restored() {\n return restored;\n },\n get pendingDraft() {\n return pendingDraft;\n },\n detach() {\n detached = true;\n clearTimeout(timer);\n editor.removeEventListener('content-change', onContentChange);\n },\n async restore(record) {\n const existing = record || pendingDraft || (await store.get(documentId));\n return applyRestore(existing);\n },\n async rename(name) {\n const trimmed = name?.trim();\n if (!trimmed) {\n throw new Error('Document name must not be empty');\n }\n nameLocked = true;\n emitName(trimmed);\n editor.metadata = {\n ...(editor.metadata || {}),\n title: trimmed,\n };\n const xml = editor.xml;\n return store.put(\n buildRecord(xml, {\n name: trimmed,\n nameLocked: true,\n }),\n );\n },\n async clear() {\n clearTimeout(timer);\n await store.delete(documentId);\n nameLocked = false;\n emitName('Untitled Document');\n },\n async getRecord() {\n return store.get(documentId);\n },\n async saveNow() {\n clearTimeout(timer);\n return persist(editor.xml);\n },\n };\n}\n"],"names":["DB_NAME","DOCUMENTS_STORE","DocumentStore","dbName","resolve","reject","request","event","db","store","mode","id","b","doc","record","GENERIC_TITLES","isGenericTitle","title","truncateTitle","text","max","cleaned","extractTitleFromXml","xml","_a","_b","elements","titleStmtTitle","articleTitle","anyTitle","el","name","node","deduceDocumentName","metadata","plainText","fallback","metaTitle","fromXml","firstLine","line","attachLocalStore","editor","options","debounceMs","force","autoRestore","onDraftAvailable","onNameChange","onRestore","format","documentId","nameLocked","currentName","timer","detached","restored","suppressingSave","pendingDraft","emitName","buildRecord","overrides","persist","scheduleSave","err","onContentChange","applyRestore","existing","filename","offerRestore","shouldRestore","onReady","trimmed"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinntec/jinntap",
3
- "version": "1.32.0",
3
+ "version": "1.33.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.es.js",
6
6
  "module": "./dist/index.es.js",
@@ -17,6 +17,9 @@
17
17
  "./jinn-toast": {
18
18
  "import": "./dist/jinn-toast.es.js",
19
19
  "types": "./dist/jinn-toast.d.ts"
20
+ },
21
+ "./storage": {
22
+ "import": "./dist/storage.es.js"
20
23
  }
21
24
  },
22
25
  "files": [
@@ -26,6 +29,8 @@
26
29
  "dist/jinn-toast.es.js",
27
30
  "dist/jinn-toast.es.js.map",
28
31
  "dist/jinn-toast.d.ts",
32
+ "dist/storage.es.js",
33
+ "dist/storage.es.js.map",
29
34
  "dist/index.es.js",
30
35
  "dist/index.es.js.map",
31
36
  "dist/index.d.ts",
@@ -50,16 +55,17 @@
50
55
  "format": "prettier --write './**/*.js' './*/**/*.json' './**/*.xq'"
51
56
  },
52
57
  "dependencies": {
53
- "@hocuspocus/provider": "^4.0.0",
54
- "@tiptap/core": "^3.22.5",
55
- "@tiptap/extension-bubble-menu": "^3.22.5",
56
- "@tiptap/extension-collaboration": "^3.22.5",
57
- "@tiptap/extension-collaboration-caret": "^3.22.5",
58
- "@tiptap/extension-history": "^3.22.5",
59
- "@tiptap/extension-image": "^3.22.5",
60
- "@tiptap/extension-placeholder": "^3.22.5",
61
- "@tiptap/pm": "^3.22.5",
62
- "@tiptap/starter-kit": "^3.22.5",
58
+ "@hocuspocus/provider": "^4.4.0",
59
+ "@tiptap/core": "^3.28.0",
60
+ "@tiptap/extension-bubble-menu": "^3.28.0",
61
+ "@tiptap/extension-collaboration": "^3.28.0",
62
+ "@tiptap/extension-collaboration-caret": "^3.28.0",
63
+ "@tiptap/extension-document": "^3.28.0",
64
+ "@tiptap/extension-image": "^3.28.0",
65
+ "@tiptap/extension-text": "^3.28.0",
66
+ "@tiptap/extensions": "^3.28.0",
67
+ "@tiptap/pm": "^3.28.0",
68
+ "@tiptap/starter-kit": "^3.28.0",
63
69
  "fontoxpath": "^3.33.2",
64
70
  "prettier-plugin-xquery": "^1.2.5",
65
71
  "rollup": "^4.62.2",
@@ -70,8 +76,8 @@
70
76
  "devDependencies": {
71
77
  "@11ty/eleventy": "^3.1.6",
72
78
  "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.2",
73
- "@hocuspocus/extension-logger": "^4.0.0",
74
- "@hocuspocus/server": "^4.0.0",
79
+ "@hocuspocus/extension-logger": "^4.4.0",
80
+ "@hocuspocus/server": "^4.4.0",
75
81
  "@semantic-release/changelog": "^6.0.3",
76
82
  "@semantic-release/git": "^10.0.1",
77
83
  "@semantic-release/github": "^12.0.9",