web-mojo 2.2.57 → 2.2.59

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.
Files changed (119) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.cjs.js.map +1 -1
  3. package/dist/admin.es.js +1 -10105
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.es.js +1 -588
  7. package/dist/auth.es.js.map +1 -1
  8. package/dist/charts.cjs.js +1 -1
  9. package/dist/charts.es.js +1 -571
  10. package/dist/charts.es.js.map +1 -1
  11. package/dist/chunks/ChatView-D4A9rIX3.js +2 -0
  12. package/dist/chunks/ChatView-D4A9rIX3.js.map +1 -0
  13. package/dist/chunks/ChatView-nxaq8aIo.js +2 -0
  14. package/dist/chunks/ChatView-nxaq8aIo.js.map +1 -0
  15. package/dist/chunks/Collection-1sPoIFvQ.js +2 -0
  16. package/dist/chunks/{Collection-DaiL0uGl.js.map → Collection-1sPoIFvQ.js.map} +1 -1
  17. package/dist/chunks/{Collection-CxbNKOas.js → Collection-DSBRXpwK.js} +2 -2
  18. package/dist/chunks/{Collection-CxbNKOas.js.map → Collection-DSBRXpwK.js.map} +1 -1
  19. package/dist/chunks/{ContextMenu-ClwHEbbD.js → ContextMenu-BWy7WqF4.js} +2 -2
  20. package/dist/chunks/{ContextMenu-ClwHEbbD.js.map → ContextMenu-BWy7WqF4.js.map} +1 -1
  21. package/dist/chunks/ContextMenu-BvniQz-N.js +3 -0
  22. package/dist/chunks/{ContextMenu-sgvgSACY.js.map → ContextMenu-BvniQz-N.js.map} +1 -1
  23. package/dist/chunks/DataView--nUWtq6r.js +2 -0
  24. package/dist/chunks/{DataView-Dzo0jbs2.js.map → DataView--nUWtq6r.js.map} +1 -1
  25. package/dist/chunks/{DataView-1xh3GFeC.js → DataView-CK3Z0TJH.js} +2 -2
  26. package/dist/chunks/{DataView-1xh3GFeC.js.map → DataView-CK3Z0TJH.js.map} +1 -1
  27. package/dist/chunks/Dialog-BcgSR01Z.js +2 -0
  28. package/dist/chunks/{Dialog-DOGDalUq.js.map → Dialog-BcgSR01Z.js.map} +1 -1
  29. package/dist/chunks/{Dialog-CQlTDhZS.js → Dialog-DwCTFV6O.js} +2 -2
  30. package/dist/chunks/{Dialog-CQlTDhZS.js.map → Dialog-DwCTFV6O.js.map} +1 -1
  31. package/dist/chunks/FormPlugins-DvQ-G5J5.js +2 -0
  32. package/dist/chunks/{FormPlugins-DY6e88YT.js.map → FormPlugins-DvQ-G5J5.js.map} +1 -1
  33. package/dist/chunks/{FormView-DaKA4Sys.js → FormView-CRmEReTC.js} +3 -3
  34. package/dist/chunks/{FormView-DaKA4Sys.js.map → FormView-CRmEReTC.js.map} +1 -1
  35. package/dist/chunks/FormView-OLA7t-yv.js +3 -0
  36. package/dist/chunks/{FormView-Dz3mYasQ.js.map → FormView-OLA7t-yv.js.map} +1 -1
  37. package/dist/chunks/ListView-6JQ6tRXs.js +2 -0
  38. package/dist/chunks/{ListView-X5w5jf51.js.map → ListView-6JQ6tRXs.js.map} +1 -1
  39. package/dist/chunks/{ListView-CDzKIpd8.js → ListView-DVStKiMi.js} +2 -2
  40. package/dist/chunks/{ListView-CDzKIpd8.js.map → ListView-DVStKiMi.js.map} +1 -1
  41. package/dist/chunks/{MetricsCountryMapView-Dx2cw7ya.js → MetricsCountryMapView-CnAEbUw_.js} +2 -2
  42. package/dist/chunks/{MetricsCountryMapView-Dx2cw7ya.js.map → MetricsCountryMapView-CnAEbUw_.js.map} +1 -1
  43. package/dist/chunks/MetricsCountryMapView-J067qrrt.js +2 -0
  44. package/dist/chunks/{MetricsCountryMapView-B2xz6zUw.js.map → MetricsCountryMapView-J067qrrt.js.map} +1 -1
  45. package/dist/chunks/{MetricsMiniChartWidget-CBuso0OE.js → MetricsMiniChartWidget-BeD1slGs.js} +2 -2
  46. package/dist/chunks/{MetricsMiniChartWidget-CBuso0OE.js.map → MetricsMiniChartWidget-BeD1slGs.js.map} +1 -1
  47. package/dist/chunks/MetricsMiniChartWidget-x2gFjHOU.js +2 -0
  48. package/dist/chunks/{MetricsMiniChartWidget-DvKd7Qrk.js.map → MetricsMiniChartWidget-x2gFjHOU.js.map} +1 -1
  49. package/dist/chunks/PDFViewer-CsyKn-gh.js +2 -0
  50. package/dist/chunks/{PDFViewer-EJ9cOfPF.js.map → PDFViewer-CsyKn-gh.js.map} +1 -1
  51. package/dist/chunks/{PDFViewer-ofMGdSaj.js → PDFViewer-DSa4BZCm.js} +2 -2
  52. package/dist/chunks/{PDFViewer-ofMGdSaj.js.map → PDFViewer-DSa4BZCm.js.map} +1 -1
  53. package/dist/chunks/Rest-DHbszkuP.js +2 -0
  54. package/dist/chunks/Rest-DHbszkuP.js.map +1 -0
  55. package/dist/chunks/Rest-Ds9e8tN8.js +2 -0
  56. package/dist/chunks/Rest-Ds9e8tN8.js.map +1 -0
  57. package/dist/chunks/TokenManager-D6SjKgPZ.js +2 -0
  58. package/dist/chunks/{TokenManager-DoN9e6q6.js.map → TokenManager-D6SjKgPZ.js.map} +1 -1
  59. package/dist/chunks/{TokenManager-Gqvj7SDX.js → TokenManager-REbha1Le.js} +2 -2
  60. package/dist/chunks/{TokenManager-Gqvj7SDX.js.map → TokenManager-REbha1Le.js.map} +1 -1
  61. package/dist/chunks/WebApp-CULZpO_0.js +2 -0
  62. package/dist/chunks/{WebApp-6qvqmOts.js.map → WebApp-CULZpO_0.js.map} +1 -1
  63. package/dist/chunks/{WebApp-_dgpwtFw.js → WebApp-DovLtA60.js} +2 -2
  64. package/dist/chunks/{WebApp-_dgpwtFw.js.map → WebApp-DovLtA60.js.map} +1 -1
  65. package/dist/chunks/WebSocketClient-B-wc3mez.js +2 -0
  66. package/dist/chunks/{WebSocketClient-DG2olXpH.js.map → WebSocketClient-B-wc3mez.js.map} +1 -1
  67. package/dist/chunks/{WebSocketClient-MFkFlSue.js → WebSocketClient-BdZ9QYll.js} +2 -2
  68. package/dist/chunks/{WebSocketClient-MFkFlSue.js.map → WebSocketClient-BdZ9QYll.js.map} +1 -1
  69. package/dist/chunks/version-C3dnl1bg.js +2 -0
  70. package/dist/chunks/version-C3dnl1bg.js.map +1 -0
  71. package/dist/chunks/{version-BVADfTA5.js → version-ioN546cp.js} +2 -2
  72. package/dist/chunks/{version-BVADfTA5.js.map → version-ioN546cp.js.map} +1 -1
  73. package/dist/css/web-mojo.css +1 -1
  74. package/dist/docit.cjs.js +1 -1
  75. package/dist/docit.es.js +1 -957
  76. package/dist/docit.es.js.map +1 -1
  77. package/dist/index.cjs.js +1 -1
  78. package/dist/index.es.js +1 -3252
  79. package/dist/index.es.js.map +1 -1
  80. package/dist/lightbox.cjs.js +1 -1
  81. package/dist/lightbox.es.js +1 -3737
  82. package/dist/lightbox.es.js.map +1 -1
  83. package/dist/loader.umd.js +2 -2
  84. package/dist/map.cjs.js +1 -1
  85. package/dist/map.es.js +1 -1032
  86. package/dist/map.es.js.map +1 -1
  87. package/dist/mojo-auth.es.js +338 -0
  88. package/dist/mojo-auth.umd.js +1 -0
  89. package/dist/timeline.cjs.js +1 -1
  90. package/dist/timeline.es.js +1 -224
  91. package/dist/timeline.es.js.map +1 -1
  92. package/dist/web-mojo.lite.iife.js +14 -3
  93. package/dist/web-mojo.lite.iife.js.map +1 -1
  94. package/dist/web-mojo.lite.iife.min.js +6 -6
  95. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  96. package/package.json +2 -2
  97. package/dist/chunks/ChatView-9k6xBWXk.js +0 -7632
  98. package/dist/chunks/ChatView-9k6xBWXk.js.map +0 -1
  99. package/dist/chunks/ChatView-CdtuCDYm.js +0 -2
  100. package/dist/chunks/ChatView-CdtuCDYm.js.map +0 -1
  101. package/dist/chunks/Collection-DaiL0uGl.js +0 -1014
  102. package/dist/chunks/ContextMenu-sgvgSACY.js +0 -1535
  103. package/dist/chunks/DataView-Dzo0jbs2.js +0 -862
  104. package/dist/chunks/Dialog-DOGDalUq.js +0 -1579
  105. package/dist/chunks/FormPlugins-DY6e88YT.js +0 -124
  106. package/dist/chunks/FormView-Dz3mYasQ.js +0 -8636
  107. package/dist/chunks/ListView-X5w5jf51.js +0 -495
  108. package/dist/chunks/MetricsCountryMapView-B2xz6zUw.js +0 -1054
  109. package/dist/chunks/MetricsMiniChartWidget-DvKd7Qrk.js +0 -3283
  110. package/dist/chunks/PDFViewer-EJ9cOfPF.js +0 -946
  111. package/dist/chunks/Rest-CgSjfMaU.js +0 -2
  112. package/dist/chunks/Rest-CgSjfMaU.js.map +0 -1
  113. package/dist/chunks/Rest-W-sPfGh9.js +0 -4375
  114. package/dist/chunks/Rest-W-sPfGh9.js.map +0 -1
  115. package/dist/chunks/TokenManager-DoN9e6q6.js +0 -1423
  116. package/dist/chunks/WebApp-6qvqmOts.js +0 -1386
  117. package/dist/chunks/WebSocketClient-DG2olXpH.js +0 -209
  118. package/dist/chunks/version-OyPGnx30.js +0 -38
  119. package/dist/chunks/version-OyPGnx30.js.map +0 -1
@@ -0,0 +1,338 @@
1
+ var v = (f, s) => () => (s || f((s = { exports: {} }).exports, s), s.exports);
2
+ var y = v((S, d) => {
3
+ (function(f, s) {
4
+ typeof define == "function" && define.amd ? define([], s) : typeof d < "u" && d.exports ? d.exports = s() : f.MojoAuth = s();
5
+ })(typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : void 0, function() {
6
+ var f = "", s = {}, c = {
7
+ access: "access_token",
8
+ refresh: "refresh_token"
9
+ }, w = {
10
+ login: "/api/login",
11
+ forgotPassword: "/api/auth/forgot",
12
+ resetWithCode: "/api/auth/password/reset/code",
13
+ resetWithToken: "/api/auth/password/reset/token",
14
+ magicSend: "/api/auth/magic/send",
15
+ magicLogin: "/api/auth/magic/login",
16
+ passkeyLoginBegin: "/api/auth/passkeys/login/begin",
17
+ passkeyLoginComplete: "/api/auth/passkeys/login/complete",
18
+ oauthBegin: "/api/auth/oauth/{provider}/begin",
19
+ oauthComplete: "/api/auth/oauth/{provider}/complete",
20
+ refreshToken: "/api/refresh_token"
21
+ };
22
+ function i(e, r) {
23
+ var t = s[e] || w[e] || "";
24
+ return r && Object.keys(r).forEach(function(n) {
25
+ t = t.replace("{" + n + "}", r[n]);
26
+ }), f.replace(/\/$/, "") + t;
27
+ }
28
+ function u(e, r, t) {
29
+ var n = Object.assign({ "Content-Type": "application/json" }, {});
30
+ return fetch(e, {
31
+ method: "POST",
32
+ headers: n,
33
+ body: JSON.stringify(r || {})
34
+ }).then(function(o) {
35
+ return o.json().then(function(a) {
36
+ if (!o.ok) throw a;
37
+ return a;
38
+ });
39
+ });
40
+ }
41
+ function m(e, r) {
42
+ return fetch(e, {
43
+ method: "GET",
44
+ headers: Object.assign({ "Content-Type": "application/json" }, {})
45
+ }).then(function(t) {
46
+ return t.json().then(function(n) {
47
+ if (!t.ok) throw n;
48
+ return n;
49
+ });
50
+ });
51
+ }
52
+ function l(e) {
53
+ var r = e && e.data ? e.data : e;
54
+ if (!r || !r.access_token) throw new Error("No access_token in response");
55
+ return localStorage.setItem(c.access, r.access_token), r.refresh_token && localStorage.setItem(c.refresh, r.refresh_token), r;
56
+ }
57
+ function k(e) {
58
+ return e ? typeof e == "string" ? e : e.message || e.error || Array.isArray(e.errors) && e.errors[0] && e.errors[0].message || "An error occurred" : "An error occurred";
59
+ }
60
+ function p(e) {
61
+ for (var r = e.replace(/-/g, "+").replace(/_/g, "/"), t = atob(r), n = new Uint8Array(t.length), o = 0; o < t.length; o++)
62
+ n[o] = t.charCodeAt(o);
63
+ return n.buffer;
64
+ }
65
+ function h(e) {
66
+ for (var r = new Uint8Array(e), t = "", n = 0; n < r.byteLength; n++)
67
+ t += String.fromCharCode(r[n]);
68
+ return btoa(t).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
69
+ }
70
+ var g = {
71
+ /**
72
+ * Initialize the library. Must be called before any auth method.
73
+ * @param {object} config
74
+ * @param {string} config.baseURL - API base URL e.g. 'https://api.example.com'
75
+ * @param {object} [config.endpoints] - Override any default endpoint paths
76
+ */
77
+ init: function(e) {
78
+ if (!e || !e.baseURL) throw new Error("MojoAuth.init: baseURL is required");
79
+ f = e.baseURL, s = Object.assign({}, e.endpoints || {});
80
+ },
81
+ // -----------------------------------------------------------------------
82
+ // JWT Login
83
+ // -----------------------------------------------------------------------
84
+ /**
85
+ * Login with username/email and password.
86
+ * Stores access_token and refresh_token in localStorage on success.
87
+ * @param {string} username
88
+ * @param {string} password
89
+ * @returns {Promise<object>} response data ({ access_token, refresh_token, user })
90
+ *
91
+ * NOTE: If MFA is enabled, the response will contain { mfa_required: true, mfa_token, mfa_methods }
92
+ * instead of tokens. Check result.mfa_required before assuming login is complete.
93
+ */
94
+ login: function(e, r) {
95
+ return u(i("login"), { username: e, password: r }).then(function(t) {
96
+ var n = t.data || t;
97
+ return n.mfa_required ? n : l(t);
98
+ });
99
+ },
100
+ // -----------------------------------------------------------------------
101
+ // Password Reset — Code method
102
+ // -----------------------------------------------------------------------
103
+ /**
104
+ * Request a 6-digit reset code sent to the user's email.
105
+ * @param {string} email
106
+ * @returns {Promise<object>}
107
+ */
108
+ forgotPasswordCode: function(e) {
109
+ return u(i("forgotPassword"), { email: e, method: "code" });
110
+ },
111
+ /**
112
+ * Complete password reset using the emailed code.
113
+ * Stores tokens on success (logs user in automatically).
114
+ * @param {string} email
115
+ * @param {string} code - 6-digit code from email
116
+ * @param {string} newPassword
117
+ * @returns {Promise<object>}
118
+ */
119
+ resetWithCode: function(e, r, t) {
120
+ return u(i("resetWithCode"), {
121
+ email: e,
122
+ code: r,
123
+ new_password: t
124
+ }).then(l);
125
+ },
126
+ // -----------------------------------------------------------------------
127
+ // Password Reset — Link / Token method
128
+ // -----------------------------------------------------------------------
129
+ /**
130
+ * Request a password reset link (pr: token) sent to the user's email.
131
+ * @param {string} email
132
+ * @returns {Promise<object>}
133
+ */
134
+ forgotPasswordLink: function(e) {
135
+ return u(i("forgotPassword"), { email: e, method: "link" });
136
+ },
137
+ /**
138
+ * Complete password reset using the token from the reset link email.
139
+ * Stores tokens on success.
140
+ * @param {string} token - pr: prefixed token from URL
141
+ * @param {string} newPassword
142
+ * @returns {Promise<object>}
143
+ */
144
+ resetWithToken: function(e, r) {
145
+ return u(i("resetWithToken"), {
146
+ token: e,
147
+ new_password: r
148
+ }).then(l);
149
+ },
150
+ // -----------------------------------------------------------------------
151
+ // Magic Login (passwordless email link)
152
+ // -----------------------------------------------------------------------
153
+ /**
154
+ * Send a magic login link (ml: token) to the user's email.
155
+ * @param {string} email
156
+ * @returns {Promise<object>}
157
+ */
158
+ sendMagicLink: function(e) {
159
+ return u(i("magicSend"), { email: e });
160
+ },
161
+ /**
162
+ * Complete login using the ml: token from the magic link URL.
163
+ * Stores tokens on success.
164
+ * @param {string} token - ml: prefixed token from URL ?token=ml:...
165
+ * @returns {Promise<object>}
166
+ */
167
+ loginWithMagicToken: function(e) {
168
+ return u(i("magicLogin"), { token: e }).then(l);
169
+ },
170
+ /**
171
+ * Convenience: read ?token= from current URL and login if it's a magic link token.
172
+ * Cleans the token from the URL after reading it.
173
+ * @returns {Promise<object|null>} resolves with auth data or null if no token found
174
+ */
175
+ handleMagicTokenFromURL: function() {
176
+ var e = new URLSearchParams(window.location.search), r = e.get("token");
177
+ if (!r || r.indexOf("ml:") !== 0) return Promise.resolve(null);
178
+ e.delete("token");
179
+ var t = e.toString() ? window.location.pathname + "?" + e.toString() : window.location.pathname;
180
+ return window.history.replaceState({}, "", t), g.loginWithMagicToken(r);
181
+ },
182
+ // -----------------------------------------------------------------------
183
+ // Passkey Login (WebAuthn)
184
+ // -----------------------------------------------------------------------
185
+ /**
186
+ * Check if WebAuthn passkeys are supported in this browser.
187
+ * @returns {boolean}
188
+ */
189
+ isPasskeySupported: function() {
190
+ return typeof window < "u" && typeof window.PublicKeyCredential < "u" && typeof navigator.credentials < "u" && typeof navigator.credentials.get == "function";
191
+ },
192
+ /**
193
+ * Login with a passkey (WebAuthn).
194
+ * Handles the full begin → browser prompt → complete flow.
195
+ * Stores tokens on success.
196
+ * @param {string} username - username or email
197
+ * @returns {Promise<object>}
198
+ */
199
+ loginWithPasskey: function(e) {
200
+ return g.isPasskeySupported() ? u(i("passkeyLoginBegin"), { username: e }).then(function(r) {
201
+ var t = r.data || r, n = t.challenge_id, o = t.publicKey;
202
+ return o.challenge = p(o.challenge), o.allowCredentials && (o.allowCredentials = o.allowCredentials.map(function(a) {
203
+ return Object.assign({}, a, { id: p(a.id) });
204
+ })), navigator.credentials.get({ publicKey: o }).then(function(a) {
205
+ if (!a) throw new Error("No credential received from authenticator");
206
+ return u(i("passkeyLoginComplete"), {
207
+ challenge_id: n,
208
+ credential: {
209
+ id: a.id,
210
+ rawId: h(a.rawId),
211
+ type: a.type,
212
+ response: {
213
+ clientDataJSON: h(a.response.clientDataJSON),
214
+ authenticatorData: h(a.response.authenticatorData),
215
+ signature: h(a.response.signature),
216
+ userHandle: a.response.userHandle ? h(a.response.userHandle) : null
217
+ }
218
+ }
219
+ });
220
+ });
221
+ }).then(l) : Promise.reject(new Error("Passkeys are not supported in this browser"));
222
+ },
223
+ // -----------------------------------------------------------------------
224
+ // Google OAuth
225
+ // -----------------------------------------------------------------------
226
+ /**
227
+ * Start Google OAuth login.
228
+ * Fetches the authorization URL from the backend and redirects the browser.
229
+ * @returns {Promise<void>}
230
+ */
231
+ startGoogleLogin: function() {
232
+ return m(i("oauthBegin", { provider: "google" })).then(function(e) {
233
+ var r = e.data || e;
234
+ if (!r.auth_url) throw new Error("No auth_url in OAuth begin response");
235
+ window.location.href = r.auth_url;
236
+ });
237
+ },
238
+ /**
239
+ * Complete Google OAuth login — call this on your OAuth callback page.
240
+ * Reads ?code and ?state from the current URL automatically.
241
+ * Stores tokens on success.
242
+ * @returns {Promise<object>}
243
+ */
244
+ completeGoogleLogin: function() {
245
+ var e = new URLSearchParams(window.location.search), r = e.get("code"), t = e.get("state");
246
+ return r ? u(i("oauthComplete", { provider: "google" }), {
247
+ code: r,
248
+ state: t
249
+ }).then(l) : Promise.reject(new Error("No OAuth code in URL"));
250
+ },
251
+ // -----------------------------------------------------------------------
252
+ // Session helpers
253
+ // -----------------------------------------------------------------------
254
+ /**
255
+ * Log out — clears tokens from localStorage.
256
+ */
257
+ logout: function() {
258
+ localStorage.removeItem(c.access), localStorage.removeItem(c.refresh);
259
+ },
260
+ /**
261
+ * Check if the user has a stored access token.
262
+ * Does not validate expiry — use getTokenPayload() for that.
263
+ * @returns {boolean}
264
+ */
265
+ isAuthenticated: function() {
266
+ return !!localStorage.getItem(c.access);
267
+ },
268
+ /**
269
+ * Get the raw access token string.
270
+ * @returns {string|null}
271
+ */
272
+ getToken: function() {
273
+ return localStorage.getItem(c.access);
274
+ },
275
+ /**
276
+ * Get the raw refresh token string.
277
+ * @returns {string|null}
278
+ */
279
+ getRefreshToken: function() {
280
+ return localStorage.getItem(c.refresh);
281
+ },
282
+ /**
283
+ * Get the Authorization header value for use in API requests.
284
+ * @returns {string|null} e.g. "Bearer eyJhbGci..."
285
+ */
286
+ getAuthHeader: function() {
287
+ var e = localStorage.getItem(c.access);
288
+ return e ? "Bearer " + e : null;
289
+ },
290
+ /**
291
+ * Decode the JWT access token payload (client-side only, no signature verification).
292
+ * @returns {object|null}
293
+ */
294
+ getTokenPayload: function() {
295
+ var e = localStorage.getItem(c.access);
296
+ if (!e) return null;
297
+ try {
298
+ var r = e.split(".");
299
+ if (r.length !== 3) return null;
300
+ var t = r[1].replace(/-/g, "+").replace(/_/g, "/"), n = 4 - t.length % 4;
301
+ return n !== 4 && (t += "====".slice(0, n)), JSON.parse(atob(t));
302
+ } catch {
303
+ return null;
304
+ }
305
+ },
306
+ /**
307
+ * Check if the stored access token is expired (based on JWT exp claim).
308
+ * Returns true if expired or if token is missing/undecodable.
309
+ * @returns {boolean}
310
+ */
311
+ isTokenExpired: function() {
312
+ var e = g.getTokenPayload();
313
+ return !e || !e.exp ? !0 : Math.floor(Date.now() / 1e3) >= e.exp;
314
+ },
315
+ /**
316
+ * Refresh the access token using the stored refresh token.
317
+ * Stores the new tokens on success.
318
+ * @returns {Promise<object>}
319
+ */
320
+ refreshToken: function() {
321
+ var e = localStorage.getItem(c.refresh);
322
+ return e ? u(i("refreshToken"), { refresh_token: e }).then(l) : Promise.reject(new Error("No refresh token stored"));
323
+ },
324
+ // -----------------------------------------------------------------------
325
+ // Error helper
326
+ // -----------------------------------------------------------------------
327
+ /**
328
+ * Extract a human-readable error message from a caught error.
329
+ * Works with the MOJO backend error shapes.
330
+ * @param {any} err - the caught error (object, string, etc.)
331
+ * @returns {string}
332
+ */
333
+ getError: k
334
+ };
335
+ return g;
336
+ });
337
+ });
338
+ export default y();
@@ -0,0 +1 @@
1
+ (function(c){typeof define=="function"&&define.amd?define(c):c()})((function(){"use strict";(function(c,f){typeof define=="function"&&define.amd?define([],f):typeof module<"u"&&module.exports?module.exports=f():c.MojoAuth=f()})(typeof globalThis<"u"?globalThis:typeof window<"u"?window:void 0,function(){var c="",f={},u={access:"access_token",refresh:"refresh_token"},p={login:"/api/login",forgotPassword:"/api/auth/forgot",resetWithCode:"/api/auth/password/reset/code",resetWithToken:"/api/auth/password/reset/token",magicSend:"/api/auth/magic/send",magicLogin:"/api/auth/magic/login",passkeyLoginBegin:"/api/auth/passkeys/login/begin",passkeyLoginComplete:"/api/auth/passkeys/login/complete",oauthBegin:"/api/auth/oauth/{provider}/begin",oauthComplete:"/api/auth/oauth/{provider}/complete",refreshToken:"/api/refresh_token"};function i(e,r){var t=f[e]||p[e]||"";return r&&Object.keys(r).forEach(function(n){t=t.replace("{"+n+"}",r[n])}),c.replace(/\/$/,"")+t}function s(e,r,t){var n=Object.assign({"Content-Type":"application/json"},{});return fetch(e,{method:"POST",headers:n,body:JSON.stringify(r||{})}).then(function(o){return o.json().then(function(a){if(!o.ok)throw a;return a})})}function w(e,r){return fetch(e,{method:"GET",headers:Object.assign({"Content-Type":"application/json"},{})}).then(function(t){return t.json().then(function(n){if(!t.ok)throw n;return n})})}function l(e){var r=e&&e.data?e.data:e;if(!r||!r.access_token)throw new Error("No access_token in response");return localStorage.setItem(u.access,r.access_token),r.refresh_token&&localStorage.setItem(u.refresh,r.refresh_token),r}function m(e){return e?typeof e=="string"?e:e.message||e.error||Array.isArray(e.errors)&&e.errors[0]&&e.errors[0].message||"An error occurred":"An error occurred"}function g(e){for(var r=e.replace(/-/g,"+").replace(/_/g,"/"),t=atob(r),n=new Uint8Array(t.length),o=0;o<t.length;o++)n[o]=t.charCodeAt(o);return n.buffer}function d(e){for(var r=new Uint8Array(e),t="",n=0;n<r.byteLength;n++)t+=String.fromCharCode(r[n]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}var h={init:function(e){if(!e||!e.baseURL)throw new Error("MojoAuth.init: baseURL is required");c=e.baseURL,f=Object.assign({},e.endpoints||{})},login:function(e,r){return s(i("login"),{username:e,password:r}).then(function(t){var n=t.data||t;return n.mfa_required?n:l(t)})},forgotPasswordCode:function(e){return s(i("forgotPassword"),{email:e,method:"code"})},resetWithCode:function(e,r,t){return s(i("resetWithCode"),{email:e,code:r,new_password:t}).then(l)},forgotPasswordLink:function(e){return s(i("forgotPassword"),{email:e,method:"link"})},resetWithToken:function(e,r){return s(i("resetWithToken"),{token:e,new_password:r}).then(l)},sendMagicLink:function(e){return s(i("magicSend"),{email:e})},loginWithMagicToken:function(e){return s(i("magicLogin"),{token:e}).then(l)},handleMagicTokenFromURL:function(){var e=new URLSearchParams(window.location.search),r=e.get("token");if(!r||r.indexOf("ml:")!==0)return Promise.resolve(null);e.delete("token");var t=e.toString()?window.location.pathname+"?"+e.toString():window.location.pathname;return window.history.replaceState({},"",t),h.loginWithMagicToken(r)},isPasskeySupported:function(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator.credentials<"u"&&typeof navigator.credentials.get=="function"},loginWithPasskey:function(e){return h.isPasskeySupported()?s(i("passkeyLoginBegin"),{username:e}).then(function(r){var t=r.data||r,n=t.challenge_id,o=t.publicKey;return o.challenge=g(o.challenge),o.allowCredentials&&(o.allowCredentials=o.allowCredentials.map(function(a){return Object.assign({},a,{id:g(a.id)})})),navigator.credentials.get({publicKey:o}).then(function(a){if(!a)throw new Error("No credential received from authenticator");return s(i("passkeyLoginComplete"),{challenge_id:n,credential:{id:a.id,rawId:d(a.rawId),type:a.type,response:{clientDataJSON:d(a.response.clientDataJSON),authenticatorData:d(a.response.authenticatorData),signature:d(a.response.signature),userHandle:a.response.userHandle?d(a.response.userHandle):null}}})})}).then(l):Promise.reject(new Error("Passkeys are not supported in this browser"))},startGoogleLogin:function(){return w(i("oauthBegin",{provider:"google"})).then(function(e){var r=e.data||e;if(!r.auth_url)throw new Error("No auth_url in OAuth begin response");window.location.href=r.auth_url})},completeGoogleLogin:function(){var e=new URLSearchParams(window.location.search),r=e.get("code"),t=e.get("state");return r?s(i("oauthComplete",{provider:"google"}),{code:r,state:t}).then(l):Promise.reject(new Error("No OAuth code in URL"))},logout:function(){localStorage.removeItem(u.access),localStorage.removeItem(u.refresh)},isAuthenticated:function(){return!!localStorage.getItem(u.access)},getToken:function(){return localStorage.getItem(u.access)},getRefreshToken:function(){return localStorage.getItem(u.refresh)},getAuthHeader:function(){var e=localStorage.getItem(u.access);return e?"Bearer "+e:null},getTokenPayload:function(){var e=localStorage.getItem(u.access);if(!e)return null;try{var r=e.split(".");if(r.length!==3)return null;var t=r[1].replace(/-/g,"+").replace(/_/g,"/"),n=4-t.length%4;return n!==4&&(t+="====".slice(0,n)),JSON.parse(atob(t))}catch{return null}},isTokenExpired:function(){var e=h.getTokenPayload();return!e||!e.exp?!0:Math.floor(Date.now()/1e3)>=e.exp},refreshToken:function(){var e=localStorage.getItem(u.refresh);return e?s(i("refreshToken"),{refresh_token:e}).then(l):Promise.reject(new Error("No refresh token stored"))},getError:m};return h})}));
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./chunks/ListView-CDzKIpd8.js"),e=require("./chunks/Rest-CgSjfMaU.js"),i=require("./chunks/Collection-CxbNKOas.js");class TimelineViewItem extends t.ListViewItem{constructor(t={}){super({className:"timeline-item",...t}),this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.template||(this.template='\n <div class="timeline-marker timeline-marker-{{markerType}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}} text-{{displayColor}}"></i>\n {{/hasIcon}}\n {{^hasIcon}}\n <div class="timeline-dot bg-{{displayColor}}"></div>\n {{/hasIcon}}\n </div>\n \n <div class="timeline-content">\n {{#showDate}}\n <div class="timeline-date text-muted small">\n {{formattedDate}}\n </div>\n {{/showDate}}\n \n <div class="timeline-card">\n {{#model.title}}\n <h6 class="timeline-title mb-1">{{model.title}}</h6>\n {{/model.title}}\n \n {{#model.description}}\n <p class="timeline-description mb-0">{{model.description}}</p>\n {{/model.description}}\n \n {{#model.meta}}\n <div class="timeline-meta mt-2 text-muted small">\n {{model.meta}}\n </div>\n {{/model.meta}}\n </div>\n </div>\n ')}async onInit(){await super.onInit(),this.processItemData()}processItemData(){this.displayColor=this.model?.get?.("color")||this.model?.color||this.theme;const t=!(!this.model?.get?.("icon")&&!this.model?.icon)&&"icon"===this.dotStyle;this.hasIcon=t,this.markerType=t?"icon":this.dotStyle;const e=this.model?.get?.("date")||this.model?.date;this.formattedDate=this.formatDate(e)}formatDate(t){if(!t)return"";switch(this.dateFormat){case"datetime":return e.dataFormatter.pipe(t,"datetime");case"relative":return e.dataFormatter.pipe(t,"timeago");default:return e.dataFormatter.pipe(t,"date")}}async onActionSelect(t,e){t.stopPropagation(),this.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model})}}class TimelineView extends t.ListView{constructor(t={}){super({className:"timeline-view",itemClass:t.itemClass||TimelineViewItem,selectionMode:"none",emptyMessage:t.emptyMessage||"No timeline events to display",template:'\n <div class="timeline-container timeline-{{position}}">\n {{#loading}}\n <div class="timeline-loading text-center py-4">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <span class="ms-2 text-muted">Loading timeline...</span>\n </div>\n {{/loading}}\n {{^loading}}\n {{#isEmpty}}\n <div class="timeline-empty text-center text-muted py-4">\n <i class="bi bi-clock-history fs-1 d-block mb-2"></i>\n <p>{{emptyMessage}}</p>\n </div>\n {{/isEmpty}}\n {{^isEmpty}}\n <div class="timeline" data-container="items"></div>\n {{/isEmpty}}\n {{/loading}}\n </div>\n ',...t}),this.position=t.position||"left",this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.groupBy=t.groupBy||"none"}_createItemView(t,e){if(this.itemViews.has(t.id))return;const i=new this.itemClass({model:t,index:e,listView:this,template:this.itemTemplate,dateFormat:this.dateFormat,dotStyle:this.dotStyle,showDate:this.showDate,theme:this.theme});return this.itemViews.set(t.id,i),i.on("item:click",this._onItemClick.bind(this)),i}_onItemClick(t){this.emit("item:click",t)}setPosition(t){return"left"!==t&&"center"!==t?(console.warn('Invalid position. Use "left" or "center"'),this):(this.position=t,this.isMounted()&&this.render(),this)}setDateFormat(t){return this.dateFormat=t,this.forEachItem(e=>{e.dateFormat=t,e.processItemData(),e.isMounted()&&e.render()}),this}setDotStyle(t){return this.dotStyle=t,this.forEachItem(e=>{e.dotStyle=t,e.processItemData(),e.isMounted()&&e.render()}),this}toggleDates(t=null){return this.showDate=null!==t?t:!this.showDate,this.forEachItem(t=>{t.showDate=this.showDate,t.isMounted()&&t.render()}),this}}exports.ListView=t.ListView,exports.ListViewItem=t.ListViewItem,exports.View=e.View,exports.Collection=i.Collection,exports.Model=i.Model,exports.TimelineView=TimelineView,exports.TimelineViewItem=TimelineViewItem;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./chunks/ListView-DVStKiMi.js"),e=require("./chunks/Rest-Ds9e8tN8.js"),i=require("./chunks/Collection-DSBRXpwK.js");class TimelineViewItem extends t.ListViewItem{constructor(t={}){super({className:"timeline-item",...t}),this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.template||(this.template='\n <div class="timeline-marker timeline-marker-{{markerType}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}} text-{{displayColor}}"></i>\n {{/hasIcon}}\n {{^hasIcon}}\n <div class="timeline-dot bg-{{displayColor}}"></div>\n {{/hasIcon}}\n </div>\n \n <div class="timeline-content">\n {{#showDate}}\n <div class="timeline-date text-muted small">\n {{formattedDate}}\n </div>\n {{/showDate}}\n \n <div class="timeline-card">\n {{#model.title}}\n <h6 class="timeline-title mb-1">{{model.title}}</h6>\n {{/model.title}}\n \n {{#model.description}}\n <p class="timeline-description mb-0">{{model.description}}</p>\n {{/model.description}}\n \n {{#model.meta}}\n <div class="timeline-meta mt-2 text-muted small">\n {{model.meta}}\n </div>\n {{/model.meta}}\n </div>\n </div>\n ')}async onInit(){await super.onInit(),this.processItemData()}processItemData(){this.displayColor=this.model?.get?.("color")||this.model?.color||this.theme;const t=!(!this.model?.get?.("icon")&&!this.model?.icon)&&"icon"===this.dotStyle;this.hasIcon=t,this.markerType=t?"icon":this.dotStyle;const e=this.model?.get?.("date")||this.model?.date;this.formattedDate=this.formatDate(e)}formatDate(t){if(!t)return"";switch(this.dateFormat){case"datetime":return e.dataFormatter.pipe(t,"datetime");case"relative":return e.dataFormatter.pipe(t,"timeago");default:return e.dataFormatter.pipe(t,"date")}}async onActionSelect(t,e){t.stopPropagation(),this.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model})}}class TimelineView extends t.ListView{constructor(t={}){super({className:"timeline-view",itemClass:t.itemClass||TimelineViewItem,selectionMode:"none",emptyMessage:t.emptyMessage||"No timeline events to display",template:'\n <div class="timeline-container timeline-{{position}}">\n {{#loading}}\n <div class="timeline-loading text-center py-4">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <span class="ms-2 text-muted">Loading timeline...</span>\n </div>\n {{/loading}}\n {{^loading}}\n {{#isEmpty}}\n <div class="timeline-empty text-center text-muted py-4">\n <i class="bi bi-clock-history fs-1 d-block mb-2"></i>\n <p>{{emptyMessage}}</p>\n </div>\n {{/isEmpty}}\n {{^isEmpty}}\n <div class="timeline" data-container="items"></div>\n {{/isEmpty}}\n {{/loading}}\n </div>\n ',...t}),this.position=t.position||"left",this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.groupBy=t.groupBy||"none"}_createItemView(t,e){if(this.itemViews.has(t.id))return;const i=new this.itemClass({model:t,index:e,listView:this,template:this.itemTemplate,dateFormat:this.dateFormat,dotStyle:this.dotStyle,showDate:this.showDate,theme:this.theme});return this.itemViews.set(t.id,i),i.on("item:click",this._onItemClick.bind(this)),i}_onItemClick(t){this.emit("item:click",t)}setPosition(t){return"left"!==t&&"center"!==t?(console.warn('Invalid position. Use "left" or "center"'),this):(this.position=t,this.isMounted()&&this.render(),this)}setDateFormat(t){return this.dateFormat=t,this.forEachItem(e=>{e.dateFormat=t,e.processItemData(),e.isMounted()&&e.render()}),this}setDotStyle(t){return this.dotStyle=t,this.forEachItem(e=>{e.dotStyle=t,e.processItemData(),e.isMounted()&&e.render()}),this}toggleDates(t=null){return this.showDate=null!==t?t:!this.showDate,this.forEachItem(t=>{t.showDate=this.showDate,t.isMounted()&&t.render()}),this}}exports.ListView=t.ListView,exports.ListViewItem=t.ListViewItem,exports.View=e.View,exports.Collection=i.Collection,exports.Model=i.Model,exports.TimelineView=TimelineView,exports.TimelineViewItem=TimelineViewItem;
2
2
  //# sourceMappingURL=timeline.cjs.js.map
@@ -1,225 +1,2 @@
1
- import { a as ListViewItem, L as ListView } from "./chunks/ListView-X5w5jf51.js";
2
- import { d as dataFormatter } from "./chunks/Rest-W-sPfGh9.js";
3
- import { V } from "./chunks/Rest-W-sPfGh9.js";
4
- import { C, M } from "./chunks/Collection-DaiL0uGl.js";
5
- class TimelineViewItem extends ListViewItem {
6
- constructor(options = {}) {
7
- super({
8
- className: "timeline-item",
9
- ...options
10
- });
11
- this.dateFormat = options.dateFormat || "date";
12
- this.dotStyle = options.dotStyle || "solid";
13
- this.showDate = options.showDate !== false;
14
- this.theme = options.theme || "primary";
15
- if (!this.template) {
16
- this.template = `
17
- <div class="timeline-marker timeline-marker-{{markerType}}">
18
- {{#hasIcon}}
19
- <i class="bi {{model.icon}} text-{{displayColor}}"></i>
20
- {{/hasIcon}}
21
- {{^hasIcon}}
22
- <div class="timeline-dot bg-{{displayColor}}"></div>
23
- {{/hasIcon}}
24
- </div>
25
-
26
- <div class="timeline-content">
27
- {{#showDate}}
28
- <div class="timeline-date text-muted small">
29
- {{formattedDate}}
30
- </div>
31
- {{/showDate}}
32
-
33
- <div class="timeline-card">
34
- {{#model.title}}
35
- <h6 class="timeline-title mb-1">{{model.title}}</h6>
36
- {{/model.title}}
37
-
38
- {{#model.description}}
39
- <p class="timeline-description mb-0">{{model.description}}</p>
40
- {{/model.description}}
41
-
42
- {{#model.meta}}
43
- <div class="timeline-meta mt-2 text-muted small">
44
- {{model.meta}}
45
- </div>
46
- {{/model.meta}}
47
- </div>
48
- </div>
49
- `;
50
- }
51
- }
52
- async onInit() {
53
- await super.onInit();
54
- this.processItemData();
55
- }
56
- processItemData() {
57
- this.displayColor = this.model?.get?.("color") || this.model?.color || this.theme;
58
- const hasIcon = !!(this.model?.get?.("icon") || this.model?.icon) && this.dotStyle === "icon";
59
- this.hasIcon = hasIcon;
60
- this.markerType = hasIcon ? "icon" : this.dotStyle;
61
- const dateValue = this.model?.get?.("date") || this.model?.date;
62
- this.formattedDate = this.formatDate(dateValue);
63
- }
64
- formatDate(date) {
65
- if (!date) return "";
66
- switch (this.dateFormat) {
67
- case "datetime":
68
- return dataFormatter.pipe(date, "datetime");
69
- case "relative":
70
- return dataFormatter.pipe(date, "timeago");
71
- default:
72
- return dataFormatter.pipe(date, "date");
73
- }
74
- }
75
- // Override to disable selection behavior in timeline
76
- async onActionSelect(event, _element) {
77
- event.stopPropagation();
78
- this.emit("item:click", {
79
- item: this,
80
- model: this.model,
81
- index: this.index,
82
- data: this.model?.toJSON ? this.model.toJSON() : this.model
83
- });
84
- if (this.listView) {
85
- this.listView.emit("item:click", {
86
- item: this,
87
- model: this.model,
88
- index: this.index,
89
- data: this.model?.toJSON ? this.model.toJSON() : this.model
90
- });
91
- }
92
- }
93
- }
94
- class TimelineView extends ListView {
95
- constructor(options = {}) {
96
- super({
97
- className: "timeline-view",
98
- itemClass: options.itemClass || TimelineViewItem,
99
- selectionMode: "none",
100
- // Timelines typically don't use selection
101
- emptyMessage: options.emptyMessage || "No timeline events to display",
102
- template: `
103
- <div class="timeline-container timeline-{{position}}">
104
- {{#loading}}
105
- <div class="timeline-loading text-center py-4">
106
- <div class="spinner-border spinner-border-sm" role="status">
107
- <span class="visually-hidden">Loading...</span>
108
- </div>
109
- <span class="ms-2 text-muted">Loading timeline...</span>
110
- </div>
111
- {{/loading}}
112
- {{^loading}}
113
- {{#isEmpty}}
114
- <div class="timeline-empty text-center text-muted py-4">
115
- <i class="bi bi-clock-history fs-1 d-block mb-2"></i>
116
- <p>{{emptyMessage}}</p>
117
- </div>
118
- {{/isEmpty}}
119
- {{^isEmpty}}
120
- <div class="timeline" data-container="items"></div>
121
- {{/isEmpty}}
122
- {{/loading}}
123
- </div>
124
- `,
125
- ...options
126
- });
127
- this.position = options.position || "left";
128
- this.dateFormat = options.dateFormat || "date";
129
- this.dotStyle = options.dotStyle || "solid";
130
- this.showDate = options.showDate !== false;
131
- this.theme = options.theme || "primary";
132
- this.groupBy = options.groupBy || "none";
133
- }
134
- /**
135
- * Override _createItemView to pass timeline-specific options
136
- */
137
- _createItemView(model, index) {
138
- if (this.itemViews.has(model.id)) return;
139
- const itemView = new this.itemClass({
140
- model,
141
- index,
142
- listView: this,
143
- template: this.itemTemplate,
144
- // Pass timeline-specific options to items
145
- dateFormat: this.dateFormat,
146
- dotStyle: this.dotStyle,
147
- showDate: this.showDate,
148
- theme: this.theme
149
- });
150
- this.itemViews.set(model.id, itemView);
151
- itemView.on("item:click", this._onItemClick.bind(this));
152
- return itemView;
153
- }
154
- /**
155
- * Handle item clicks (replaces selection behavior)
156
- */
157
- _onItemClick(event) {
158
- this.emit("item:click", event);
159
- }
160
- /**
161
- * Update timeline position
162
- */
163
- setPosition(position) {
164
- if (position !== "left" && position !== "center") {
165
- console.warn('Invalid position. Use "left" or "center"');
166
- return this;
167
- }
168
- this.position = position;
169
- if (this.isMounted()) {
170
- this.render();
171
- }
172
- return this;
173
- }
174
- /**
175
- * Update date format for all items
176
- */
177
- setDateFormat(format) {
178
- this.dateFormat = format;
179
- this.forEachItem((itemView) => {
180
- itemView.dateFormat = format;
181
- itemView.processItemData();
182
- if (itemView.isMounted()) {
183
- itemView.render();
184
- }
185
- });
186
- return this;
187
- }
188
- /**
189
- * Update dot style for all items
190
- */
191
- setDotStyle(style) {
192
- this.dotStyle = style;
193
- this.forEachItem((itemView) => {
194
- itemView.dotStyle = style;
195
- itemView.processItemData();
196
- if (itemView.isMounted()) {
197
- itemView.render();
198
- }
199
- });
200
- return this;
201
- }
202
- /**
203
- * Toggle date display
204
- */
205
- toggleDates(show = null) {
206
- this.showDate = show !== null ? show : !this.showDate;
207
- this.forEachItem((itemView) => {
208
- itemView.showDate = this.showDate;
209
- if (itemView.isMounted()) {
210
- itemView.render();
211
- }
212
- });
213
- return this;
214
- }
215
- }
216
- export {
217
- C as Collection,
218
- ListView,
219
- ListViewItem,
220
- M as Model,
221
- TimelineView,
222
- TimelineViewItem,
223
- V as View
224
- };
1
+ import{a as t,L as e}from"./chunks/ListView-6JQ6tRXs.js";import{d as i}from"./chunks/Rest-DHbszkuP.js";import{V as s}from"./chunks/Rest-DHbszkuP.js";import{C as n,M as o}from"./chunks/Collection-1sPoIFvQ.js";class TimelineViewItem extends t{constructor(t={}){super({className:"timeline-item",...t}),this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.template||(this.template='\n <div class="timeline-marker timeline-marker-{{markerType}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}} text-{{displayColor}}"></i>\n {{/hasIcon}}\n {{^hasIcon}}\n <div class="timeline-dot bg-{{displayColor}}"></div>\n {{/hasIcon}}\n </div>\n \n <div class="timeline-content">\n {{#showDate}}\n <div class="timeline-date text-muted small">\n {{formattedDate}}\n </div>\n {{/showDate}}\n \n <div class="timeline-card">\n {{#model.title}}\n <h6 class="timeline-title mb-1">{{model.title}}</h6>\n {{/model.title}}\n \n {{#model.description}}\n <p class="timeline-description mb-0">{{model.description}}</p>\n {{/model.description}}\n \n {{#model.meta}}\n <div class="timeline-meta mt-2 text-muted small">\n {{model.meta}}\n </div>\n {{/model.meta}}\n </div>\n </div>\n ')}async onInit(){await super.onInit(),this.processItemData()}processItemData(){this.displayColor=this.model?.get?.("color")||this.model?.color||this.theme;const t=!(!this.model?.get?.("icon")&&!this.model?.icon)&&"icon"===this.dotStyle;this.hasIcon=t,this.markerType=t?"icon":this.dotStyle;const e=this.model?.get?.("date")||this.model?.date;this.formattedDate=this.formatDate(e)}formatDate(t){if(!t)return"";switch(this.dateFormat){case"datetime":return i.pipe(t,"datetime");case"relative":return i.pipe(t,"timeago");default:return i.pipe(t,"date")}}async onActionSelect(t,e){t.stopPropagation(),this.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model})}}class TimelineView extends e{constructor(t={}){super({className:"timeline-view",itemClass:t.itemClass||TimelineViewItem,selectionMode:"none",emptyMessage:t.emptyMessage||"No timeline events to display",template:'\n <div class="timeline-container timeline-{{position}}">\n {{#loading}}\n <div class="timeline-loading text-center py-4">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <span class="ms-2 text-muted">Loading timeline...</span>\n </div>\n {{/loading}}\n {{^loading}}\n {{#isEmpty}}\n <div class="timeline-empty text-center text-muted py-4">\n <i class="bi bi-clock-history fs-1 d-block mb-2"></i>\n <p>{{emptyMessage}}</p>\n </div>\n {{/isEmpty}}\n {{^isEmpty}}\n <div class="timeline" data-container="items"></div>\n {{/isEmpty}}\n {{/loading}}\n </div>\n ',...t}),this.position=t.position||"left",this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.groupBy=t.groupBy||"none"}_createItemView(t,e){if(this.itemViews.has(t.id))return;const i=new this.itemClass({model:t,index:e,listView:this,template:this.itemTemplate,dateFormat:this.dateFormat,dotStyle:this.dotStyle,showDate:this.showDate,theme:this.theme});return this.itemViews.set(t.id,i),i.on("item:click",this._onItemClick.bind(this)),i}_onItemClick(t){this.emit("item:click",t)}setPosition(t){return"left"!==t&&"center"!==t?(console.warn('Invalid position. Use "left" or "center"'),this):(this.position=t,this.isMounted()&&this.render(),this)}setDateFormat(t){return this.dateFormat=t,this.forEachItem(e=>{e.dateFormat=t,e.processItemData(),e.isMounted()&&e.render()}),this}setDotStyle(t){return this.dotStyle=t,this.forEachItem(e=>{e.dotStyle=t,e.processItemData(),e.isMounted()&&e.render()}),this}toggleDates(t=null){return this.showDate=null!==t?t:!this.showDate,this.forEachItem(t=>{t.showDate=this.showDate,t.isMounted()&&t.render()}),this}}export{n as Collection,e as ListView,t as ListViewItem,o as Model,TimelineView,TimelineViewItem,s as View};
225
2
  //# sourceMappingURL=timeline.es.js.map