@rsmlamongan/user-menu 0.0.0-stage → 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,631 @@
1
+ import { a as e, i as t, n, o as r, r as i, t as a } from "./validation-ZwudKvW7.js";
2
+ import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createSlots as f, createTextVNode as p, createVNode as m, defineComponent as h, effectScope as g, getCurrentInstance as _, inject as v, isRef as y, mergeModels as b, nextTick as x, onBeforeUnmount as S, onMounted as C, openBlock as w, reactive as T, ref as E, renderList as D, renderSlot as O, toDisplayString as k, unref as A, useId as j, useModel as M, useSlots as N, watch as P, withCtx as F, withModifiers as I } from "vue";
3
+ import { VAlert as L, VBtn as R, VCard as z, VCardActions as B, VCardText as V, VDialog as H, VNavigationDrawer as U, VProgressCircular as W, VTextField as G } from "vuetify/components";
4
+ //#region src/plugin.ts
5
+ var K = Symbol("rsml-user-menu-options");
6
+ function q(e) {
7
+ return { install(t) {
8
+ i(e.appId), t.provide(K, e);
9
+ } };
10
+ }
11
+ function ee() {
12
+ let e = v(K);
13
+ if (!e) throw Error("Install createUserMenu() before using RSML User Menu.");
14
+ return e;
15
+ }
16
+ //#endregion
17
+ //#region src/state.ts
18
+ function te(o, c, l) {
19
+ i(o.appId);
20
+ let u = g(!0), d = 0, f = !1, p = "drawer", m = null, h = 0, _ = 0, v = 0, y = [], b = l?.getItems() !== void 0, x = !1, S = s(o.getSession);
21
+ function C() {
22
+ let e = l?.getCreate?.();
23
+ if (e !== void 0) return e;
24
+ let t = o.api;
25
+ return typeof t?.createFavorite == "function" ? t.createFavorite.bind(t) : void 0;
26
+ }
27
+ function w() {
28
+ let e = l?.getSave?.();
29
+ if (e !== void 0) return e;
30
+ let t = o.api;
31
+ return typeof t?.saveFavoriteChanges == "function" ? t.saveFavoriteChanges.bind(t) : void 0;
32
+ }
33
+ let E = s(() => l?.getItems() !== void 0 || typeof o.api?.listFavorites == "function"), D = s(() => typeof C() == "function"), O = s(() => typeof w() == "function"), k = T({
34
+ open: !1,
35
+ loading: !1,
36
+ loaded: !1,
37
+ busy: !1,
38
+ favorites: [],
39
+ error: "",
40
+ notice: "",
41
+ editing: !1,
42
+ draft: [],
43
+ adding: !1,
44
+ addTitle: "",
45
+ addUrl: "",
46
+ addError: "",
47
+ confirmDiscard: !1
48
+ }), A = s(() => k.editing ? JSON.stringify(k.draft.map((e) => e.id)) !== JSON.stringify(y.map((e) => e.id)) : k.adding && k.addTitle.trim().length > 0);
49
+ function j(e = !1) {
50
+ d++, h++, _++, y = [], x = !1, Object.assign(k, {
51
+ open: !1,
52
+ loading: !1,
53
+ loaded: !1,
54
+ busy: !1,
55
+ favorites: [],
56
+ error: "",
57
+ notice: "",
58
+ editing: !1,
59
+ draft: [],
60
+ adding: !1,
61
+ addTitle: "",
62
+ addUrl: "",
63
+ addError: "",
64
+ confirmDiscard: !1
65
+ }), e && c?.(!1, !0);
66
+ }
67
+ u.run(() => P(() => JSON.stringify([S.value?.key, S.value?.user.id]), (e, t) => j(t !== void 0), {
68
+ immediate: !0,
69
+ flush: "sync"
70
+ }));
71
+ function M(e) {
72
+ JSON.stringify(e) !== JSON.stringify(k.favorites) && _++, k.favorites = e;
73
+ }
74
+ function N(e) {
75
+ b !== (e !== void 0) && _++, b = e !== void 0;
76
+ }
77
+ function F() {
78
+ return k.editing && v !== _;
79
+ }
80
+ function I(t) {
81
+ try {
82
+ M(n(t)), k.loaded = !0, k.error = F() ? r(new e("conflict"), "") : "";
83
+ } catch (e) {
84
+ _++, k.favorites = [], k.loaded = !1, k.error = r(e, "Daftar favorit dari aplikasi tidak valid.");
85
+ }
86
+ }
87
+ u.run(() => P(() => l?.getItems(), (e) => {
88
+ (e !== void 0 || b) && (h++, k.loading = !1, N(e), x = !1, S.value && (k.open || k.loaded) && (e === void 0 ? (k.loaded = !1, k.open && (k.busy ? x = !0 : L())) : I(e)));
89
+ }, { deep: !0 }));
90
+ async function L() {
91
+ if (f || !S.value || k.loading || k.busy) return;
92
+ let t = l?.getItems();
93
+ if (N(t), t !== void 0) {
94
+ I(t);
95
+ return;
96
+ }
97
+ let i = o.api;
98
+ if (typeof i?.listFavorites != "function") {
99
+ k.loaded = !1, k.error = "Daftar favorit belum tersedia.";
100
+ return;
101
+ }
102
+ let a = i.listFavorites.bind(i), s = d, c = ++h;
103
+ k.loading = !0, k.loaded = !1, k.error = "";
104
+ try {
105
+ let t = n(await a());
106
+ s === d && c === h && (M(t), k.loaded = !0, F() && (k.error = r(new e("conflict"), "")));
107
+ } catch (e) {
108
+ s === d && c === h && (k.error = r(e, "Daftar favorit belum dapat dimuat. Coba lagi."));
109
+ } finally {
110
+ s === d && c === h && (k.loading = !1);
111
+ }
112
+ }
113
+ function R(e) {
114
+ e === d && (k.busy = !1, x && (x = !1, k.open && L()));
115
+ }
116
+ function z() {
117
+ l?.getItems() !== void 0 && l.onItemsChange(n(k.favorites));
118
+ }
119
+ function B() {
120
+ k.busy || (k.editing = !1, k.draft = [], y = [], k.error = "");
121
+ }
122
+ function V() {
123
+ k.open = !1, k.adding = !1, k.confirmDiscard = !1, B();
124
+ }
125
+ function H(e) {
126
+ return !f && (e && S.value && !k.open ? (m = typeof document < "u" && document.activeElement instanceof HTMLElement ? document.activeElement : null, k.open = !0, L()) : !e && k.open && !k.busy && (p = "drawer", A.value ? k.confirmDiscard = !0 : V()), c?.(k.open), k.open);
127
+ }
128
+ function U() {
129
+ k.busy || (p === "add" ? W() : V(), k.confirmDiscard = !1, c?.(k.open));
130
+ }
131
+ function W() {
132
+ k.busy || (k.adding = !1, k.addTitle = "", k.addUrl = "", k.addError = "");
133
+ }
134
+ function G() {
135
+ k.busy || (p = "add", A.value ? k.confirmDiscard = !0 : W());
136
+ }
137
+ function K() {
138
+ if (!(!k.loaded || k.busy || k.loading || k.adding)) {
139
+ if (!O.value) {
140
+ k.error = "Pengubahan favorit belum tersedia.";
141
+ return;
142
+ }
143
+ k.draft = n(k.favorites), y = n(k.favorites), v = _, k.editing = !0, k.error = "", k.notice = "";
144
+ }
145
+ }
146
+ function q(e, t) {
147
+ if (!k.editing || k.busy || t < 0 || t >= k.draft.length) return;
148
+ let n = k.draft.findIndex((t) => t.id === e);
149
+ if (n < 0 || n === t) return;
150
+ let [r] = k.draft.splice(n, 1);
151
+ k.draft.splice(t, 0, r), k.notice = `${r.title} dipindahkan ke urutan ${t + 1}.`;
152
+ }
153
+ function ee(e) {
154
+ k.editing && !k.busy && (k.draft = k.draft.filter((t) => t.id !== e));
155
+ }
156
+ async function te() {
157
+ if (!k.editing || k.busy) return;
158
+ if (F()) {
159
+ k.error = r(new e("conflict"), "");
160
+ return;
161
+ }
162
+ let t = d, i = _;
163
+ k.busy = !0, k.error = "";
164
+ let a = k.draft.map((e) => e.id), o = y.filter((e) => !a.includes(e.id)).map((e) => e.id);
165
+ try {
166
+ let r = w();
167
+ if (typeof r != "function") throw new e("unavailable");
168
+ let s = n(await r({
169
+ orderedIds: a,
170
+ deletedIds: o
171
+ }));
172
+ if (t === d) {
173
+ if (i !== _) throw new e("conflict");
174
+ M(s), k.editing = !1, k.draft = [], y = [], k.notice = "Perubahan favorit disimpan.", z();
175
+ }
176
+ } catch (e) {
177
+ t === d && (k.error = r(e, "Perubahan belum dapat disimpan. Draft tetap tersedia."));
178
+ } finally {
179
+ R(t);
180
+ }
181
+ }
182
+ function J() {
183
+ if (!(!k.loaded || k.loading || k.busy || k.editing)) {
184
+ if (!D.value) {
185
+ k.error = "Penambahan favorit belum tersedia.";
186
+ return;
187
+ }
188
+ k.error = "", k.notice = "";
189
+ try {
190
+ let n = o.getCurrentPage();
191
+ if (k.addTitle = i(n.title), k.addUrl = t(n.url), k.favorites.some((e) => e.url === k.addUrl)) throw new e("duplicate");
192
+ k.addError = "", k.adding = !0;
193
+ } catch (e) {
194
+ k.error = r(e, "Halaman ini belum dapat ditambahkan. Coba lagi.");
195
+ }
196
+ }
197
+ }
198
+ async function Y() {
199
+ if (!k.adding || k.busy) return;
200
+ let s = d, c = _;
201
+ k.addError = "";
202
+ try {
203
+ let r = C();
204
+ if (typeof r != "function") throw new e("unavailable");
205
+ let l = {
206
+ title: i(k.addTitle),
207
+ url: t(k.addUrl),
208
+ appId: o.appId
209
+ };
210
+ k.busy = !0;
211
+ let u = a(await r(l));
212
+ if (s === d) {
213
+ if (c !== _) throw new e("conflict");
214
+ M(n([...k.favorites, u])), k.adding = !1, k.notice = "Halaman ditambahkan ke favorit.", z();
215
+ }
216
+ } catch (e) {
217
+ s === d && (k.addError = r(e, "Favorit belum dapat disimpan. Coba lagi."));
218
+ } finally {
219
+ R(s);
220
+ }
221
+ }
222
+ async function X() {
223
+ if (k.busy || k.editing || !o.settings || !S.value) return;
224
+ let e = d;
225
+ k.busy = !0, k.error = "";
226
+ try {
227
+ if (o.settings.onClick) await o.settings.onClick();
228
+ else {
229
+ let e = new URL(o.settings.url, window.location.href);
230
+ window.location.assign(t(e.href));
231
+ }
232
+ } catch {
233
+ e === d && (k.error = "Pengaturan belum dapat dibuka. Coba lagi.");
234
+ } finally {
235
+ R(e);
236
+ }
237
+ }
238
+ return {
239
+ state: k,
240
+ session: S,
241
+ dirty: A,
242
+ canLoad: E,
243
+ canCreate: D,
244
+ canSave: O,
245
+ options: o,
246
+ requestVisibility: H,
247
+ load: L,
248
+ startEdit: K,
249
+ cancelEdit: B,
250
+ move: q,
251
+ remove: ee,
252
+ save: te,
253
+ startAdd: J,
254
+ add: Y,
255
+ cancelAdd: W,
256
+ requestCloseAdd: G,
257
+ discard: U,
258
+ openSettings: X,
259
+ restoreFocus: () => {
260
+ m?.isConnected && m.focus();
261
+ },
262
+ dispose: () => {
263
+ f = !0, j(), u.stop();
264
+ }
265
+ };
266
+ }
267
+ //#endregion
268
+ //#region src/components/UserMenuHost.vue?vue&type=script&setup=true&lang.ts
269
+ var J = ["aria-busy"], Y = {
270
+ key: 0,
271
+ class: "rsml-user-menu__slot-header"
272
+ }, X = { class: "rsml-user-menu__body" }, ne = { class: "rsml-user-menu__heading-row" }, re = { class: "rsml-user-menu__heading-actions" }, ie = ["disabled"], ae = {
273
+ key: 0,
274
+ class: "rsml-user-menu__hint"
275
+ }, oe = {
276
+ key: 2,
277
+ class: "rsml-user-menu__empty",
278
+ role: "status"
279
+ }, se = {
280
+ key: 0,
281
+ class: "rsml-user-menu__list",
282
+ "aria-label": "Draft favorit"
283
+ }, ce = ["data-favorite-id", "onDrop"], le = { class: "rsml-user-menu__edit-title" }, ue = [
284
+ "draggable",
285
+ "disabled",
286
+ "aria-label",
287
+ "onDragstart"
288
+ ], de = { class: "rsml-user-menu__text" }, fe = { class: "rsml-user-menu__meta" }, pe = { class: "rsml-user-menu__item-actions" }, me = [
289
+ "disabled",
290
+ "aria-label",
291
+ "onClick"
292
+ ], he = [
293
+ "disabled",
294
+ "aria-label",
295
+ "onClick"
296
+ ], ge = {
297
+ key: 1,
298
+ class: "rsml-user-menu__list",
299
+ "aria-label": "Daftar favorit"
300
+ }, _e = ["data-favorite-id"], ve = ["href"], ye = { class: "rsml-user-menu__meta" }, be = {
301
+ key: 2,
302
+ class: "rsml-user-menu__empty"
303
+ }, xe = {
304
+ key: 0,
305
+ class: "rsml-user-menu__muted"
306
+ }, Se = {
307
+ class: "rsml-user-menu__status",
308
+ role: "status",
309
+ "aria-live": "polite"
310
+ }, Ce = {
311
+ key: 4,
312
+ class: "rsml-user-menu__actions"
313
+ }, we = { class: "rsml-user-menu__slot-footer" }, Te = ["id"], Ee = { class: "rsml-user-menu__url" }, De = ["id"], Z = /* @__PURE__ */ h({
314
+ __name: "UserMenuHost",
315
+ props: /*@__PURE__*/ b({
316
+ items: {},
317
+ onCreate: { type: Function },
318
+ onSave: { type: Function }
319
+ }, {
320
+ modelValue: {
321
+ type: Boolean,
322
+ required: !0
323
+ },
324
+ modelModifiers: {}
325
+ }),
326
+ emits: /*@__PURE__*/ b(["update:items"], ["update:modelValue"]),
327
+ setup(e, { emit: t }) {
328
+ let n = e, r = t, i = N(), a = M(e, "modelValue"), h = _(), g = !1, v = !0, b = !1, T = te(ee(), (e, t) => {
329
+ v && (t && !g && (b = !0), t ? h.emit("update:modelValue", e) : a.value !== e && (a.value = e));
330
+ }, {
331
+ getItems: () => n.items,
332
+ onItemsChange: (e) => r("update:items", e),
333
+ getCreate: () => n.onCreate,
334
+ getSave: () => n.onSave
335
+ }), K = T.state, q = j(), Z = E(null), Q = E(null), Oe = s(() => K.busy || K.editing || !T.options.settings || !T.session.value), $ = "";
336
+ function ke(e) {
337
+ e.key !== "Escape" || !K.open || K.adding || K.confirmDiscard || (e.preventDefault(), T.requestVisibility(!1));
338
+ }
339
+ let Ae = P(a, (e) => {
340
+ g && T.requestVisibility(e);
341
+ }, { flush: "sync" });
342
+ C(() => {
343
+ g = !0, window.addEventListener("keydown", ke), T.requestVisibility(!b && a.value);
344
+ }), S(() => {
345
+ v = !1, g = !1, Ae(), window.removeEventListener("keydown", ke), T.dispose();
346
+ }), P(() => K.open, async (e) => {
347
+ await x(), v && (e ? Z.value?.focus() : T.restoreFocus());
348
+ }), P(() => K.editing, async () => {
349
+ await x(), v && K.open && Q.value?.querySelector("[data-edit-action]")?.focus();
350
+ });
351
+ function je(e, t) {
352
+ if (K.busy) return e.preventDefault();
353
+ $ = t, e.dataTransfer?.setData("text/plain", t), e.dataTransfer && (e.dataTransfer.effectAllowed = "move");
354
+ }
355
+ function Me(e, t) {
356
+ e.preventDefault(), $ && e.dataTransfer?.getData("text/plain") === $ && T.move($, t), $ = "";
357
+ }
358
+ async function Ne(e, t) {
359
+ T.remove(e), await x();
360
+ let n = Q.value?.querySelectorAll("[data-drag-handle]");
361
+ (n?.[Math.min(t, (n?.length ?? 0) - 1)] ?? Q.value?.querySelector("[data-edit-action]"))?.focus();
362
+ }
363
+ return (e, t) => (w(), u(o, null, [
364
+ m(A(U), {
365
+ "model-value": A(K).open,
366
+ class: "rsml-user-menu",
367
+ temporary: "",
368
+ touchless: "",
369
+ "disable-resize-watcher": "",
370
+ "disable-route-watcher": "",
371
+ location: "right",
372
+ width: 360,
373
+ persistent: A(K).busy,
374
+ "capture-focus": !A(K).adding && !A(K).confirmDiscard,
375
+ "retain-focus": A(K).open && !A(K).adding && !A(K).confirmDiscard,
376
+ role: "dialog",
377
+ "aria-modal": "true",
378
+ "aria-hidden": !A(K).open,
379
+ "aria-label": "Menu pengguna",
380
+ "onUpdate:modelValue": t[3] ||= (e) => A(T).requestVisibility(e)
381
+ }, f({
382
+ default: F(() => [d("div", {
383
+ ref_key: "content",
384
+ ref: Q,
385
+ class: "rsml-user-menu__panel",
386
+ "aria-busy": A(K).loading || A(K).busy
387
+ }, [i.header ? (w(), u("div", Y, [O(e.$slots, "header")])) : l("", !0), d("div", X, [
388
+ d("div", ne, [d("h2", null, k(A(K).editing ? "Edit favorit" : "Favorit saya"), 1), d("div", re, [A(K).editing ? l("", !0) : (w(), c(A(R), {
389
+ key: 0,
390
+ "data-edit-action": "",
391
+ variant: "text",
392
+ size: "small",
393
+ disabled: !A(K).loaded || A(K).loading || A(K).busy || !A(K).favorites.length || !A(T).canSave.value,
394
+ onClick: A(T).startEdit
395
+ }, {
396
+ default: F(() => [...t[9] ||= [p("Edit favorit", -1)]]),
397
+ _: 1
398
+ }, 8, ["disabled", "onClick"])), d("button", {
399
+ ref_key: "closeButton",
400
+ ref: Z,
401
+ type: "button",
402
+ class: "rsml-user-menu__control",
403
+ "aria-label": "Tutup menu pengguna",
404
+ disabled: A(K).busy,
405
+ onClick: t[0] ||= (e) => A(T).requestVisibility(!1)
406
+ }, [...t[10] ||= [d("span", { "aria-hidden": "true" }, "×", -1)]], 8, ie)])]),
407
+ A(K).editing ? (w(), u("p", ae, " Geser pegangan atau gunakan tombol naik dan turun untuk mengatur urutan. ")) : l("", !0),
408
+ A(K).error ? (w(), c(A(L), {
409
+ key: 1,
410
+ type: "error",
411
+ icon: !1,
412
+ variant: "tonal",
413
+ class: "rsml-user-menu__alert",
414
+ role: "alert"
415
+ }, {
416
+ default: F(() => [p(k(A(K).error) + " ", 1), A(K).loaded ? l("", !0) : (w(), c(A(R), {
417
+ key: 0,
418
+ variant: "text",
419
+ disabled: A(K).loading || !A(T).canLoad.value,
420
+ onClick: A(T).load
421
+ }, {
422
+ default: F(() => [...t[11] ||= [p("Coba lagi", -1)]]),
423
+ _: 1
424
+ }, 8, ["disabled", "onClick"]))]),
425
+ _: 1
426
+ })) : l("", !0),
427
+ A(K).loading ? (w(), u("div", oe, [m(A(W), {
428
+ indeterminate: "",
429
+ size: "24",
430
+ color: "primary",
431
+ "aria-label": "Memuat favorit"
432
+ }), t[12] ||= d("p", null, "Memuat favorit…", -1)])) : A(K).loaded ? (w(), u(o, { key: 3 }, [A(K).editing ? (w(), u("ol", se, [(w(!0), u(o, null, D(A(K).draft, (e, n) => (w(), u("li", {
433
+ key: e.id,
434
+ "data-favorite-id": e.id,
435
+ class: "rsml-user-menu__edit-item",
436
+ onDragover: t[2] ||= I(() => {}, ["prevent"]),
437
+ onDrop: (e) => Me(e, n)
438
+ }, [d("div", le, [d("button", {
439
+ type: "button",
440
+ class: "rsml-user-menu__control rsml-user-menu__drag",
441
+ "data-drag-handle": "",
442
+ draggable: !A(K).busy,
443
+ disabled: A(K).busy,
444
+ "aria-label": `Geser ${e.title}`,
445
+ onDragstart: (t) => je(t, e.id),
446
+ onDragend: t[1] ||= (e) => y($) ? $.value = "" : $ = ""
447
+ }, [...t[13] ||= [d("span", { "aria-hidden": "true" }, "⠿", -1)]], 40, ue), d("span", de, [d("strong", null, k(e.title), 1), d("span", fe, k(e.appId), 1)])]), d("div", pe, [
448
+ d("button", {
449
+ type: "button",
450
+ class: "rsml-user-menu__control",
451
+ disabled: A(K).busy || n === 0,
452
+ "aria-label": `Naikkan ${e.title}`,
453
+ onClick: (t) => A(T).move(e.id, n - 1)
454
+ }, " ↑ ", 8, me),
455
+ d("button", {
456
+ type: "button",
457
+ class: "rsml-user-menu__control",
458
+ disabled: A(K).busy || n === A(K).draft.length - 1,
459
+ "aria-label": `Turunkan ${e.title}`,
460
+ onClick: (t) => A(T).move(e.id, n + 1)
461
+ }, " ↓ ", 8, he),
462
+ m(A(R), {
463
+ variant: "text",
464
+ size: "small",
465
+ disabled: A(K).busy,
466
+ "aria-label": `Hapus ${e.title}`,
467
+ onClick: (t) => Ne(e.id, n)
468
+ }, {
469
+ default: F(() => [...t[14] ||= [p("Hapus", -1)]]),
470
+ _: 1
471
+ }, 8, [
472
+ "disabled",
473
+ "aria-label",
474
+ "onClick"
475
+ ])
476
+ ])], 40, ce))), 128))])) : (w(), u("ol", ge, [(w(!0), u(o, null, D(A(K).favorites, (e) => (w(), u("li", {
477
+ key: e.id,
478
+ "data-favorite-id": e.id
479
+ }, [d("a", {
480
+ href: e.url,
481
+ class: "rsml-user-menu__link"
482
+ }, [d("strong", null, k(e.title), 1), d("span", ye, k(e.appId), 1)], 8, ve)], 8, _e))), 128))])), (A(K).editing ? !A(K).draft.length : !A(K).favorites.length) ? (w(), u("div", be, [d("p", null, k(A(K).editing ? "Semua favorit akan dihapus setelah disimpan." : "Belum ada favorit."), 1), A(K).editing ? l("", !0) : (w(), u("p", xe, " Simpan halaman yang sering Anda gunakan di sini. "))])) : l("", !0)], 64)) : l("", !0),
483
+ d("p", Se, k(A(K).notice), 1),
484
+ A(K).editing ? (w(), u("div", Ce, [m(A(R), {
485
+ "data-edit-action": "",
486
+ variant: "text",
487
+ disabled: A(K).busy,
488
+ onClick: A(T).cancelEdit
489
+ }, {
490
+ default: F(() => [...t[15] ||= [p("Batal", -1)]]),
491
+ _: 1
492
+ }, 8, ["disabled", "onClick"]), m(A(R), {
493
+ color: "primary",
494
+ loading: A(K).busy,
495
+ disabled: A(K).busy || !A(T).dirty.value || !A(T).canSave.value,
496
+ onClick: A(T).save
497
+ }, {
498
+ default: F(() => [...t[16] ||= [p("Simpan", -1)]]),
499
+ _: 1
500
+ }, 8, [
501
+ "loading",
502
+ "disabled",
503
+ "onClick"
504
+ ])])) : (w(), c(A(R), {
505
+ key: 5,
506
+ block: "",
507
+ color: "primary",
508
+ variant: "tonal",
509
+ disabled: !A(K).loaded || A(K).loading || A(K).busy || !A(T).canCreate.value,
510
+ onClick: A(T).startAdd
511
+ }, {
512
+ default: F(() => [...t[17] ||= [p("Tambahkan halaman ini", -1)]]),
513
+ _: 1
514
+ }, 8, ["disabled", "onClick"]))
515
+ ])], 8, J)]),
516
+ _: 2
517
+ }, [i.footer || A(T).options.settings ? {
518
+ name: "append",
519
+ fn: F(() => [d("div", we, [O(e.$slots, "footer", {
520
+ openSettings: A(T).openSettings,
521
+ settingsDisabled: Oe.value
522
+ }, () => [A(T).options.settings ? (w(), c(A(R), {
523
+ key: 0,
524
+ block: "",
525
+ variant: "text",
526
+ disabled: Oe.value,
527
+ onClick: A(T).openSettings
528
+ }, {
529
+ default: F(() => [p(k(A(T).options.settings.label), 1)]),
530
+ _: 1
531
+ }, 8, ["disabled", "onClick"])) : l("", !0)])])]),
532
+ key: "0"
533
+ } : void 0]), 1032, [
534
+ "model-value",
535
+ "persistent",
536
+ "capture-focus",
537
+ "retain-focus",
538
+ "aria-hidden"
539
+ ]),
540
+ m(A(H), {
541
+ "model-value": A(K).adding,
542
+ persistent: A(K).busy,
543
+ "max-width": "440",
544
+ "aria-labelledby": `${A(q)}-add`,
545
+ "onUpdate:modelValue": t[6] ||= (e) => !e && A(T).requestCloseAdd()
546
+ }, {
547
+ default: F(() => [m(A(z), { class: "rsml-user-menu rsml-user-menu__dialog" }, {
548
+ default: F(() => [d("form", { onSubmit: t[5] ||= I((...e) => A(T).add && A(T).add(...e), ["prevent"]) }, [m(A(V), null, {
549
+ default: F(() => [
550
+ d("h2", { id: `${A(q)}-add` }, "Tambahkan favorit", 8, Te),
551
+ t[18] ||= d("p", { class: "rsml-user-menu__hint" }, "Simpan halaman ini agar mudah ditemukan kembali.", -1),
552
+ m(A(G), {
553
+ modelValue: A(K).addTitle,
554
+ "onUpdate:modelValue": t[4] ||= (e) => A(K).addTitle = e,
555
+ label: "Judul favorit",
556
+ autofocus: "",
557
+ disabled: A(K).busy,
558
+ "error-messages": A(K).addError
559
+ }, null, 8, [
560
+ "modelValue",
561
+ "disabled",
562
+ "error-messages"
563
+ ]),
564
+ t[19] ||= d("p", { class: "rsml-user-menu__muted" }, "URL halaman", -1),
565
+ d("p", Ee, k(A(K).addUrl), 1)
566
+ ]),
567
+ _: 1
568
+ }), m(A(B), null, {
569
+ default: F(() => [m(A(R), {
570
+ variant: "text",
571
+ disabled: A(K).busy,
572
+ onClick: A(T).cancelAdd
573
+ }, {
574
+ default: F(() => [...t[20] ||= [p("Batal", -1)]]),
575
+ _: 1
576
+ }, 8, ["disabled", "onClick"]), m(A(R), {
577
+ type: "submit",
578
+ color: "primary",
579
+ variant: "flat",
580
+ loading: A(K).busy,
581
+ disabled: A(K).busy || !A(T).canCreate.value
582
+ }, {
583
+ default: F(() => [...t[21] ||= [p("Tambahkan", -1)]]),
584
+ _: 1
585
+ }, 8, ["loading", "disabled"])]),
586
+ _: 1
587
+ })], 32)]),
588
+ _: 1
589
+ })]),
590
+ _: 1
591
+ }, 8, [
592
+ "model-value",
593
+ "persistent",
594
+ "aria-labelledby"
595
+ ]),
596
+ m(A(H), {
597
+ "model-value": A(K).confirmDiscard,
598
+ "max-width": "400",
599
+ "aria-labelledby": `${A(q)}-discard`,
600
+ "onUpdate:modelValue": t[8] ||= (e) => A(K).confirmDiscard = e
601
+ }, {
602
+ default: F(() => [m(A(z), { class: "rsml-user-menu rsml-user-menu__dialog" }, {
603
+ default: F(() => [m(A(V), null, {
604
+ default: F(() => [d("h2", { id: `${A(q)}-discard` }, "Buang perubahan?", 8, De), t[22] ||= d("p", { class: "rsml-user-menu__hint" }, "Perubahan Anda belum disimpan.", -1)]),
605
+ _: 1
606
+ }), m(A(B), null, {
607
+ default: F(() => [m(A(R), {
608
+ variant: "text",
609
+ onClick: t[7] ||= (e) => A(K).confirmDiscard = !1
610
+ }, {
611
+ default: F(() => [...t[23] ||= [p("Lanjutkan edit", -1)]]),
612
+ _: 1
613
+ }), m(A(R), {
614
+ color: "error",
615
+ variant: "flat",
616
+ onClick: A(T).discard
617
+ }, {
618
+ default: F(() => [...t[24] ||= [p("Buang perubahan", -1)]]),
619
+ _: 1
620
+ }, 8, ["onClick"])]),
621
+ _: 1
622
+ })]),
623
+ _: 1
624
+ })]),
625
+ _: 1
626
+ }, 8, ["model-value", "aria-labelledby"])
627
+ ], 64));
628
+ }
629
+ });
630
+ //#endregion
631
+ export { e as UserMenuError, Z as UserMenuHost, q as createUserMenu };
package/dist/mock.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { Favorite, UserMenuApi, UserMenuOptions } from "./types.js";
2
+ export type MockOperation = keyof UserMenuApi;
3
+ export interface MockUserMenuApiOptions {
4
+ getSession: UserMenuOptions["getSession"];
5
+ storage?: Pick<Storage, "getItem" | "setItem">;
6
+ storageKey?: string;
7
+ initialFavorites?: Record<string, readonly Favorite[]>;
8
+ latencyMs?: number | (() => number);
9
+ shouldFail?: (operation: MockOperation) => boolean;
10
+ }
11
+ export declare function createMockUserMenuApi(options: MockUserMenuApiOptions): UserMenuApi;
package/dist/mock.js ADDED
@@ -0,0 +1,58 @@
1
+ import { a as e, i as t, n, r } from "./validation-ZwudKvW7.js";
2
+ //#region src/mock.ts
3
+ function i(i) {
4
+ let a = i.storageKey ?? "rsml-user-menu:mock:v1";
5
+ function o() {
6
+ return i.storage ?? globalThis.localStorage;
7
+ }
8
+ function s(e) {
9
+ return `${a}:${encodeURIComponent(e)}`;
10
+ }
11
+ function c(e, t) {
12
+ o().setItem(s(e), JSON.stringify(t));
13
+ }
14
+ function l(e, t = !1) {
15
+ let r = o().getItem(s(e));
16
+ if (r !== null) return n(JSON.parse(r));
17
+ let a = i.initialFavorites, l = n(a && Object.hasOwn(a, e) ? [...a[e] ?? []] : []);
18
+ return t && c(e, l), l;
19
+ }
20
+ async function u(t, n) {
21
+ try {
22
+ let a = i.getSession();
23
+ if (!a) throw new e("unauthenticated");
24
+ let o = r(a.user.id), s = typeof i.latencyMs == "function" ? i.latencyMs() : i.latencyMs, c = i.shouldFail?.(t);
25
+ if (s && Number.isFinite(s) && s > 0 && await new Promise((e) => setTimeout(e, s)), c) throw new e("unavailable");
26
+ return n(o);
27
+ } catch (t) {
28
+ throw t instanceof e ? t : new e("unavailable");
29
+ }
30
+ }
31
+ return {
32
+ listFavorites: () => u("listFavorites", (e) => l(e, !0)),
33
+ createFavorite(n) {
34
+ let i = { ...n };
35
+ return u("createFavorite", (n) => {
36
+ let a = {
37
+ id: Array.from(crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16)), (e) => e.toString(16).padStart(2, "0")).join(""),
38
+ title: r(i.title),
39
+ url: t(i.url),
40
+ appId: r(i.appId)
41
+ }, o = l(n);
42
+ if (o.some((e) => e.url === a.url)) throw new e("duplicate");
43
+ return c(n, [...o, a]), { ...a };
44
+ });
45
+ },
46
+ saveFavoriteChanges(t) {
47
+ let r = [...t.orderedIds], i = [...t.deletedIds];
48
+ return u("saveFavoriteChanges", (t) => {
49
+ let a = l(t), o = [...r, ...i];
50
+ if (o.length !== a.length || new Set(o).size !== o.length || o.some((e) => !a.some((t) => t.id === e))) throw new e("conflict");
51
+ let s = new Map(a.map((e) => [e.id, e])), u = r.map((e) => s.get(e));
52
+ return c(t, u), n(u);
53
+ });
54
+ }
55
+ };
56
+ }
57
+ //#endregion
58
+ export { i as createMockUserMenuApi };