@rsmlamongan/user-menu 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +61 -0
- package/README.md +273 -2
- package/dist/components/UserMenuHost.vue.d.ts +33 -0
- package/dist/errors.d.ts +6 -0
- package/dist/http.d.ts +17 -0
- package/dist/http.js +70 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +631 -0
- package/dist/mock.d.ts +11 -0
- package/dist/mock.js +58 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/state.d.ts +56 -0
- package/dist/style.css +2 -0
- package/dist/types.d.ts +52 -0
- package/dist/validation-ZwudKvW7.js +49 -0
- package/dist/validation.d.ts +5 -0
- package/docs/API-CONTRACT.md +221 -0
- package/docs/DEVELOPMENT.md +258 -0
- package/docs/RELEASING.md +114 -0
- package/package.json +92 -4
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 };
|