@wssto2/vue-core 0.4.24 → 0.4.26

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 (58) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/{AccessGate.vue_vue_type_script_setup_true_lang-DcbZBINh.js → AccessGate.vue_vue_type_script_setup_true_lang-J5HoyGNJ.js} +1 -1
  3. package/dist/{Activity-CI-l_OFl.js → Activity-B6R8Jghz.js} +2 -2
  4. package/dist/{Changes-BdR0R20V.js → Changes-BQG7IV49.js} +2 -2
  5. package/dist/{CollectionPage.vue_vue_type_script_setup_true_lang-BNM_cbXa.js → CollectionPage.vue_vue_type_script_setup_true_lang-BrbQ0Y5d.js} +1 -1
  6. package/dist/{DeadLetters-CRTeoZS1.js → DeadLetters-CJZSWjsn.js} +4 -4
  7. package/dist/{General-hdmVP72B.js → General-tsRC866T.js} +2 -2
  8. package/dist/{NewRolePage-BPeKasOp.js → NewRolePage-L57Zg1Mg.js} +2 -2
  9. package/dist/PhotoViewer.vue_vue_type_script_setup_true_lang-CY5EZiyK.js +433 -0
  10. package/dist/{ProfilePage-Dq9lcO5O.js → ProfilePage-B9WUrImn.js} +2 -2
  11. package/dist/{RoleEditor.vue_vue_type_script_setup_true_lang-B6g2760V.js → RoleEditor.vue_vue_type_script_setup_true_lang-Hr0WgL1K.js} +2 -2
  12. package/dist/{RolePage-BYH-0fVI.js → RolePage-uezn-Og1.js} +3 -3
  13. package/dist/{RolesPage-BRm5xDw7.js → RolesPage-DkMAJZR6.js} +2 -2
  14. package/dist/{SectionNavigator.vue_vue_type_script_setup_true_lang-BltrQnrQ.js → SectionNavigator.vue_vue_type_script_setup_true_lang-BYRc0-qh.js} +1 -1
  15. package/dist/{Sessions-B1eKG_I2.js → Sessions-BDu3nMmz.js} +2 -2
  16. package/dist/{SettingsPage-0P38Ty4w.js → SettingsPage-CA7YCy6K.js} +2 -2
  17. package/dist/{SignIn-Dp8Ji0_r.js → SignIn-DQzS20kM.js} +2 -2
  18. package/dist/{SignInPage-CiStJboK.js → SignInPage-ft3unWwX.js} +2 -2
  19. package/dist/{SignIns-Bo7R2Coi.js → SignIns-C3h_YIkc.js} +2 -2
  20. package/dist/{UserRecord-DGq_PPy1.js → UserRecord-BO5-wsYt.js} +5 -5
  21. package/dist/{UsersList-BulNu4aE.js → UsersList-D3b3DGN5.js} +4 -4
  22. package/dist/access/index.js +1 -1
  23. package/dist/app/index.js +5 -5
  24. package/dist/collection/index.js +3 -3
  25. package/dist/{contributions-DsfmDoRD.js → contributions-BVBZP5Jb.js} +1 -1
  26. package/dist/form/index.js +1 -1
  27. package/dist/{guards-Dve61KjR.js → guards-BJZjc3FZ.js} +1 -1
  28. package/dist/{http-D_D9YbLH.js → http-BFfkA7gN.js} +1 -1
  29. package/dist/identity/index.js +1 -1
  30. package/dist/{index-BmowiT1y.js → index-BVU76sBO.js} +12 -12
  31. package/dist/{index-tnSTp0cM.js → index-C3CzOub7.js} +2 -2
  32. package/dist/{index-Yy28omu6.js → index-CvJSAsfk.js} +5 -5
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.js +1 -1
  35. package/dist/{navigation-Cm3iChlR.js → navigation-DpcDF0rX.js} +1 -1
  36. package/dist/{neighbors-DVN_cADL.js → neighbors-RVQ4O3Qv.js} +1 -1
  37. package/dist/notifications/index.js +1 -1
  38. package/dist/overlay/PhotoViewer.vue.d.ts +4 -3
  39. package/dist/overlay/PhotoViewerAction.vue.d.ts +22 -0
  40. package/dist/overlay/index.d.ts +1 -0
  41. package/dist/overlay/index.js +47 -23
  42. package/dist/page/index.js +1 -1
  43. package/dist/platform/index.d.ts +25 -1
  44. package/dist/platform/index.js +59 -49
  45. package/dist/platform/platform.d.ts +9 -5
  46. package/dist/platform/session.d.ts +10 -0
  47. package/dist/platform/sessionUser.d.ts +8 -0
  48. package/dist/platform-PZpUkkMS.js +268 -0
  49. package/dist/router/index.js +3 -3
  50. package/dist/{sections-D-kD98vu.js → sections-CeZl-Jxg.js} +1 -1
  51. package/dist/shell/index.js +3 -3
  52. package/dist/{status-Bh3-Cg7o.js → status-8KH7PITT.js} +2 -2
  53. package/dist/styles.css +1 -1
  54. package/dist/testing/index.js +1 -1
  55. package/dist/testing/platform.d.ts +10 -7
  56. package/package.json +3 -2
  57. package/dist/PhotoViewer.vue_vue_type_script_setup_true_lang-QPCW3Xi6.js +0 -411
  58. package/dist/platform-q3cjODLx.js +0 -255
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.26 — 2026-10-12
4
+
5
+ A typed platform declared once, and the signed-in user changed in place. From ARV cutover g (the step f map, wave 2 step 0). Three items, one commit each.
6
+
7
+ ### Requires
8
+ - go-core unchanged: **`v1.7.0`**; **`vue` 3.5.19 or later**.
9
+
10
+ ### Added
11
+ - **`PlatformRegistry`** (`@wssto2/vue-core/platform`): the app says once what its session user and bootstrap config are, as it does for permissions: `declare module "@wssto2/vue-core/platform" { interface PlatformRegistry { user: ArvUser; config: ArvConfig } }`. Bare `Platform` (what `usePlatform()`, `createApplication({ platform })`, `createTestPlatform()` and `createTestSession()` use) is then `Platform<ArvUser, ArvConfig>`; a key left out falls back to `SessionUser` / `BootstrapConfig` (`RegisteredUser` and `RegisteredConfig` are exported). `createPlatform<U, C>` stays generic. **Moving from explicit generics:** declare the registry once, then drop the casts at every `usePlatform()` read and `Platform<User, Config>` annotations (they still compile: the same type). Checked by `typing.test-d.ts` (not augmented) and `test-data/registry` (augmented; `npm run typecheck:registry`, part of `check`).
12
+ - **`useSessionUser()`**: the signed-in user as a readonly computed ref, typed from the registry, `null` unless authenticated (a held, expired session is not a signed-in user). The impersonator stays on `session.state`. No `useSession()` reader: `usePlatform().session` is enough. ARV: the 39 files reading `useAuthStore().user` can read it.
13
+ - **`session.update(patch)`**: `patch` is `Partial<Pick<SessionSnapshot, "user" | "access" | "navigation">>` (`SessionPatch`). It replaces those parts of a signed-in session and keeps the status, `expiresAt`, impersonator and the rest. It is not a change of who is signed in: nothing in flight is cancelled and no late answer is dropped (a `refresh()` already asked still lands with the server's version). Reactive readers (`useSessionUser`, the access client, the application's locale-from-user) see the new value. A no-op unless authenticated; a `user.id` other than the signed-in one **throws** (a programming error: a different person is `session.establish`). ARV: `useAuthStore.write()` becomes `session.update(...)`, so a language or profile save no longer re-establishes the session.
14
+
15
+ ### Changes to existing behaviour
16
+ - **Bare `Platform` follows the registry.** Without an augmentation nothing changes. With one, a platform built with another user type no longer fits bare `Platform`. `createTestPlatform({ config })` must then give the registered config's own fields (the test has no other source for them). ARV: `frontend/tests/app/features.test.ts` and `frontend/tests/support/arvApp.ts` (`createTestPlatform`) once the registry declares `config`.
17
+ - **Pinned by tests that were updated:** none.
18
+
19
+ ## 0.4.25 — 2026-10-12
20
+
21
+ The photo viewer's actions on a phone. From ARV cutover g (wave 1, the vehicle gallery). Two items, one commit each.
22
+
23
+ ### Requires
24
+ - go-core unchanged: **`v1.7.0`**; **`vue` 3.5.19 or later**.
25
+
26
+ ### Added
27
+ - **`PhotoViewerAction`** (`@wssto2/vue-core/overlay`): the content of `PhotoViewer`'s `#actions` slot. `label`, `tone?: "critical"` (the destructive one, in the danger colour), `disabled?` (stays focusable, `aria-disabled`, emits nothing); emits `select`. A 44 px text button made for the viewer's dark surface, contrast-tested. ARV: `VehiclePhotoGallery.vue` replaces its hand-styled `<button>`s ("Postavi kao naslovnu", "Obriši") and their `text-xs` with two `PhotoViewerAction`s, `data-test` kept.
28
+
29
+ ### Changes to existing behaviour
30
+ - **On a phone the `#actions` move to a bottom toolbar.** Where `useCompactPresentation()` is true the slot renders once, in a centred toolbar (`data-test="photo-toolbar"`, safe-area aware) between the photo and the thumbnail strip; the header keeps the counter, rotate, download and close. On a wide screen nothing changes (the actions stay in the header). No `#actions`, no toolbar. ARV: the vehicle gallery's viewer (390 px: the counter is no longer cut to "2." and the actions no longer shrink).
31
+ - **The counter is never cut.** In the header only the title truncates; the counter stays whole.
32
+ - **Pinned by tests that were updated:** none.
33
+
3
34
  ## 0.4.24 — 2026-10-11
4
35
 
5
36
  A refusal in the server's words, a dialog that only shows, a new record with a start. From ARV cutover e8a (both lanes). Three items, one commit each.
@@ -1,5 +1,5 @@
1
1
  import { defineComponent as t, computed as i, renderSlot as n } from "vue";
2
- import { u as l } from "./platform-q3cjODLx.js";
2
+ import { u as l } from "./platform-PZpUkkMS.js";
3
3
  const m = /* @__PURE__ */ t({
4
4
  __name: "AccessGate",
5
5
  props: {
@@ -6,8 +6,8 @@ import { u as O } from "./format-D8X4zsx6.js";
6
6
  import { _ as U } from "./DateField.vue_vue_type_script_setup_true_lang-CpuH0WTl.js";
7
7
  import { _ as T } from "./FormGroup.vue_vue_type_script_setup_true_lang-DSwSRsA5.js";
8
8
  import { e as z } from "./control-B4SdblL6.js";
9
- import { P as G, c as H, i as J } from "./index-BmowiT1y.js";
10
- import { u as K } from "./platform-q3cjODLx.js";
9
+ import { P as G, c as H, i as J } from "./index-BVU76sBO.js";
10
+ import { u as K } from "./platform-PZpUkkMS.js";
11
11
  import { b as M } from "./routeResource-DlTsGTg_.js";
12
12
  import { _ as Q } from "./AsyncSection.vue_vue_type_script_setup_true_lang-Blj6KgCr.js";
13
13
  import { _ as W } from "./Badge.vue_vue_type_script_setup_true_lang-DJyZc0C7.js";
@@ -1,7 +1,7 @@
1
1
  import { defineComponent as k, computed as N, openBlock as n, createBlock as u, unref as a, withCtx as g, createElementBlock as p, Fragment as _, renderList as $, createElementVNode as i, toDisplayString as h, createCommentVNode as C, ref as x, watch as b, createVNode as y } from "vue";
2
2
  import { useI18n as E } from "vue-i18n";
3
- import { P as V, i as R } from "./index-BmowiT1y.js";
4
- import { u as S } from "./platform-q3cjODLx.js";
3
+ import { P as V, i as R } from "./index-BVU76sBO.js";
4
+ import { u as S } from "./platform-PZpUkkMS.js";
5
5
  import { b as B } from "./routeResource-DlTsGTg_.js";
6
6
  import { _ as F } from "./AsyncSection.vue_vue_type_script_setup_true_lang-Blj6KgCr.js";
7
7
  import { u as L } from "./useLoad-M7V-AVwR.js";
@@ -1,7 +1,7 @@
1
1
  import { hasInjectionContext as lt, inject as ot, shallowRef as xe, computed as k, watch as Ve, toValue as Se, ref as ie, getCurrentScope as nt, onScopeDispose as st, defineComponent as be, openBlock as u, createElementBlock as y, createVNode as O, unref as t, createElementVNode as i, toDisplayString as g, Fragment as ee, renderList as le, createCommentVNode as F, createBlock as W, mergeProps as ve, withCtx as q, createTextVNode as G, normalizeClass as ue, useTemplateRef as fe, withModifiers as Ke, withDirectives as Le, vModelText as Fe, nextTick as at, onBeforeUnmount as rt, onMounted as it, renderSlot as ge, useSlots as We, createSlots as Qe, normalizeProps as Xe, guardReactiveProps as Je } from "vue";
2
2
  import { routerKey as ct } from "vue-router";
3
3
  import { i as qe, a as ut } from "./error-CD7x0Jrz.js";
4
- import { a as dt, d as Re, o as ft, L as Te, e as je, w as pt, b as vt } from "./http-D_D9YbLH.js";
4
+ import { a as dt, d as Re, o as ft, L as Te, e as je, w as pt, b as vt } from "./http-BFfkA7gN.js";
5
5
  import { a as mt } from "./AdaptivePageShell.vue_vue_type_script_setup_true_lang-CxU9aNRQ.js";
6
6
  import { useI18n as he } from "vue-i18n";
7
7
  import { _ as ce, u as Ne } from "./Button.vue_vue_type_script_setup_true_lang-CL9Qh5yq.js";
@@ -1,15 +1,15 @@
1
1
  import { defineComponent as B, useTemplateRef as C, computed as y, ref as v, openBlock as D, createBlock as z, unref as r, withCtx as m, createVNode as F, createElementVNode as b, normalizeClass as $, toDisplayString as h } from "vue";
2
2
  import { useI18n as q } from "vue-i18n";
3
3
  import { a as k } from "./error-CD7x0Jrz.js";
4
- import { u as V, _ as N } from "./CollectionPage.vue_vue_type_script_setup_true_lang-BNM_cbXa.js";
4
+ import { u as V, _ as N } from "./CollectionPage.vue_vue_type_script_setup_true_lang-BrbQ0Y5d.js";
5
5
  import { u as P } from "./describeError-B-NMa--w.js";
6
6
  import { u as I } from "./format-D8X4zsx6.js";
7
- import { e as a, R as O } from "./index-tnSTp0cM.js";
7
+ import { e as a, R as O } from "./index-C3CzOub7.js";
8
8
  import { _ as W } from "./AlertDialog.vue_vue_type_script_setup_true_lang-whA4WLdl.js";
9
9
  import { t as i } from "./toast-CqSDTWRX.js";
10
10
  import { u as Y } from "./useLoad-M7V-AVwR.js";
11
- import { u as j } from "./platform-q3cjODLx.js";
12
- import { a as G, r as H } from "./http-D_D9YbLH.js";
11
+ import { u as j } from "./platform-PZpUkkMS.js";
12
+ import { a as G, r as H } from "./http-BFfkA7gN.js";
13
13
  function J(u) {
14
14
  return G({
15
15
  id: "events.deadletters",
@@ -8,9 +8,9 @@ import { _ as F } from "./FormView.vue_vue_type_script_setup_true_lang-BUrYkjmF.
8
8
  import { _ as L } from "./SelectField.vue_vue_type_script_setup_true_lang-C3FbRQW7.js";
9
9
  import { _ as f } from "./TextField.vue_vue_type_script_setup_true_lang-CP2WeU36.js";
10
10
  import { u as A } from "./useSaveChrome-7huA3FzR.js";
11
- import { P as D, b as G, i as I } from "./index-BmowiT1y.js";
11
+ import { P as D, b as G, i as I } from "./index-BVU76sBO.js";
12
12
  import { t as M } from "./toast-CqSDTWRX.js";
13
- import { u as O } from "./platform-q3cjODLx.js";
13
+ import { u as O } from "./platform-PZpUkkMS.js";
14
14
  import { b as U } from "./routeResource-DlTsGTg_.js";
15
15
  import { u as j } from "./fieldMessages-6HVzSDqG.js";
16
16
  import { _ as $ } from "./ActionRow.vue_vue_type_script_setup_true_lang-QPvYudWc.js";
@@ -4,8 +4,8 @@ import { useRoute as k, useRouter as R } from "vue-router";
4
4
  import { a as $ } from "./AdaptivePageShell.vue_vue_type_script_setup_true_lang-CxU9aNRQ.js";
5
5
  import { _ as b } from "./AsyncSection.vue_vue_type_script_setup_true_lang-Blj6KgCr.js";
6
6
  import { u as g } from "./useLoad-M7V-AVwR.js";
7
- import { a as x, c as u } from "./index-Yy28omu6.js";
8
- import { _ as P } from "./RoleEditor.vue_vue_type_script_setup_true_lang-B6g2760V.js";
7
+ import { a as x, c as u } from "./index-CvJSAsfk.js";
8
+ import { _ as P } from "./RoleEditor.vue_vue_type_script_setup_true_lang-Hr0WgL1K.js";
9
9
  const V = /* @__PURE__ */ _({
10
10
  __name: "NewRolePage",
11
11
  setup(h) {
@@ -0,0 +1,433 @@
1
+ import { defineComponent as Ne, useModel as Xe, ref as k, useTemplateRef as se, watch as Q, computed as g, onBeforeUnmount as Ve, nextTick as ye, onMounted as Ye, openBlock as h, createBlock as Ze, Teleport as je, createElementBlock as m, createVNode as C, Transition as Ee, withCtx as Ke, unref as s, createElementVNode as p, toDisplayString as ee, createCommentVNode as w, renderSlot as be, normalizeClass as M, withModifiers as re, normalizeStyle as te, Fragment as We, renderList as Ue, mergeModels as _e } from "vue";
2
+ import { useI18n as Fe } from "vue-i18n";
3
+ import { _ as I } from "./Icon.vue_vue_type_script_lang-D7oC-d-S.js";
4
+ import { u as He } from "./mediaQuery-CygcXmFW.js";
5
+ import { u as qe } from "./useDialog-CXR3hN0G.js";
6
+ const ke = [1, 1.5, 2, 3, 4, 5], Me = 1, ue = 5, Ge = (a) => Math.min(ue, Math.max(Me, a)), ze = (a, l) => l % 2 === 0 ? a : { width: a.height, height: a.width };
7
+ function Je(a, l, r) {
8
+ const i = ze(a, r);
9
+ if (i.width <= 0 || i.height <= 0 || l.width <= 0 || l.height <= 0) return { width: 0, height: 0 };
10
+ const o = Math.min(l.width / i.width, l.height / i.height);
11
+ return { width: a.width * o, height: a.height * o };
12
+ }
13
+ function Qe(a, l, r) {
14
+ return { x: Math.max(0, (a.width * r - l.width) / 2), y: Math.max(0, (a.height * r - l.height) / 2) };
15
+ }
16
+ function X(a, l, r, i) {
17
+ const o = Qe(l, r, i);
18
+ return { x: Math.min(o.x, Math.max(-o.x, a.x)) + 0, y: Math.min(o.y, Math.max(-o.y, a.y)) + 0 };
19
+ }
20
+ function et(a, l, r, i, o) {
21
+ const z = Ge(l), u = z / a.zoom, $ = { x: r.x - (r.x - a.pan.x) * u, y: r.y - (r.y - a.pan.y) * u };
22
+ return { zoom: z, pan: X($, i, o, z) };
23
+ }
24
+ function tt(a, l) {
25
+ return l === 1 ? ke.find((i) => i > a + 1e-3) ?? ue : [...ke].reverse().find((i) => i < a - 1e-3) ?? Me;
26
+ }
27
+ function at(a, l, r, i, o) {
28
+ const z = Math.min(o.width / a.width, o.height / a.height), u = { width: a.width * z, height: a.height * z }, $ = { width: a.width * r, height: a.height * r }, T = { width: Math.min(1, l.width / $.width), height: Math.min(1, l.height / $.height) }, O = { x: 0.5 - i.x / $.width, y: 0.5 - i.y / $.height };
29
+ return {
30
+ image: u,
31
+ view: { x: (O.x - T.width / 2) * u.width, y: (O.y - T.height / 2) * u.height, width: T.width * u.width, height: T.height * u.height }
32
+ };
33
+ }
34
+ function it(a, l, r, i) {
35
+ return X({ x: (0.5 - a.x) * l.width * i, y: (0.5 - a.y) * l.height * i }, l, r, i);
36
+ }
37
+ const ot = {
38
+ key: 0,
39
+ class: "relative z-9999"
40
+ }, nt = ["aria-label"], lt = {
41
+ "data-test": "photo-header",
42
+ class: "flex items-center gap-2 px-4 pt-[max(0.875rem,var(--app-safe-top))] pb-3.5 md:px-4.5"
43
+ }, st = { class: "flex min-w-0 text-headline font-semibold" }, rt = {
44
+ key: 0,
45
+ class: "truncate"
46
+ }, ut = {
47
+ key: 1,
48
+ class: "shrink-0 whitespace-pre"
49
+ }, ct = {
50
+ class: "shrink-0 whitespace-nowrap",
51
+ "aria-live": "polite",
52
+ "data-test": "photo-counter"
53
+ }, dt = ["aria-label", "aria-disabled"], ht = {
54
+ class: "w-13 text-center text-subheadline tabular-nums compact:hidden",
55
+ "data-test": "zoom-percent"
56
+ }, vt = ["aria-label", "aria-disabled"], mt = ["aria-label"], pt = ["href", "download", "aria-label"], ft = ["aria-label"], gt = { class: "flex min-h-0 grow items-center gap-4 px-4 md:px-4.5" }, wt = ["aria-label", "aria-disabled"], xt = ["src", "alt"], yt = ["src"], bt = ["aria-label", "aria-disabled"], _t = {
57
+ key: 0,
58
+ "data-test": "photo-toolbar",
59
+ class: "flex shrink-0 items-center justify-center gap-2 px-4 pt-3 pb-1"
60
+ }, kt = ["aria-label", "aria-current", "onClick"], Mt = ["src"], zt = {
61
+ key: 2,
62
+ class: "h-[max(1.25rem,var(--app-safe-bottom))] shrink-0"
63
+ }, $t = {
64
+ class: "sr-only",
65
+ "aria-live": "polite"
66
+ }, Pt = 8, Ct = 300, B = "flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-full bg-white/8 text-[#f1f5f3] transition-colors duration-motion-fast hover:bg-white/16 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#6ee7b7] aria-disabled:cursor-default aria-disabled:opacity-30 aria-disabled:hover:bg-white/8", Bt = /* @__PURE__ */ Ne({
67
+ __name: "PhotoViewer",
68
+ props: /* @__PURE__ */ _e({
69
+ items: {},
70
+ title: { default: void 0 }
71
+ }, {
72
+ index: { default: 0 },
73
+ indexModifiers: {}
74
+ }),
75
+ emits: /* @__PURE__ */ _e(["presented", "dismissed"], ["update:index"]),
76
+ setup(a, { expose: l, emit: r }) {
77
+ const i = a, o = Xe(a, "index"), z = r, { t: u } = Fe(), $ = He(), T = k(null), O = se("stage"), $e = se("image"), ce = se("strip"), E = qe(T, { initialFocus: "panel", onPresented: () => z("presented"), onDismissed: () => z("dismissed") }), { isOpen: K } = E, ae = k(!1);
78
+ Q(K, (e) => {
79
+ e && (ae.value = !0);
80
+ }, { flush: "sync" });
81
+ const Pe = () => {
82
+ K.value || (ae.value = !1);
83
+ }, d = k(1), c = k({ x: 0, y: 0 }), P = k(0), W = k({ width: 0, height: 0 }), x = k({ width: 0, height: 0 }), b = k(0), ie = k(!1), V = k(null), v = g(() => i.items[o.value]), D = g(() => Je(W.value, x.value, P.value)), L = g(() => ze(D.value, P.value)), de = g(() => D.value.width > 0), Ce = g(() => Math.round(d.value * 100)), A = g(() => d.value > 1.001), he = g(() => o.value > 0), ve = g(() => o.value < i.items.length - 1), Te = g(() => ({
84
+ width: `${D.value.width}px`,
85
+ height: `${D.value.height}px`,
86
+ marginLeft: `${-D.value.width / 2}px`,
87
+ marginTop: `${-D.value.height / 2}px`,
88
+ transform: `translate(${c.value.x + b.value}px, ${c.value.y}px) scale(${d.value}) rotate(${P.value * 90}deg)`
89
+ }));
90
+ function U() {
91
+ d.value = 1, c.value = { x: 0, y: 0 }, b.value = 0;
92
+ }
93
+ function F() {
94
+ const e = O.value;
95
+ e && (x.value = { width: e.clientWidth, height: e.clientHeight }), oe();
96
+ }
97
+ function oe() {
98
+ const e = $e.value;
99
+ e && e.naturalWidth > 0 && (W.value = { width: e.naturalWidth, height: e.naturalHeight });
100
+ }
101
+ let H = null;
102
+ Q(O, (e) => {
103
+ H?.disconnect(), e && (F(), typeof ResizeObserver < "u" && (H = new ResizeObserver(() => {
104
+ F(), c.value = X(c.value, L.value, x.value, d.value);
105
+ }), H.observe(e)));
106
+ }), Ve(() => H?.disconnect()), Q(o, () => {
107
+ U(), P.value = 0, W.value = { width: 0, height: 0 }, ye(() => {
108
+ oe(), ce.value?.querySelector("[aria-current=true]")?.scrollIntoView?.({ inline: "center", block: "nearest" });
109
+ });
110
+ }), Q(() => i.items.length, (e) => {
111
+ e === 0 ? E.dismiss() : o.value > e - 1 && (o.value = e - 1);
112
+ });
113
+ function Oe(e = 0) {
114
+ o.value = Math.min(Math.max(0, e), Math.max(0, i.items.length - 1)), U(), P.value = 0, W.value = { width: 0, height: 0 }, V.value = null, E.present(), ye(F);
115
+ }
116
+ const me = () => E.dismiss();
117
+ l({ present: Oe, dismiss: me });
118
+ function Y(e) {
119
+ const t = o.value + e;
120
+ t < 0 || t > i.items.length - 1 || (V.value = e === 1 ? "forward" : "back", o.value = t);
121
+ }
122
+ function R(e) {
123
+ q(tt(d.value, e), { x: 0, y: 0 });
124
+ }
125
+ function q(e, t) {
126
+ const n = et({ zoom: d.value, pan: c.value }, e, t, L.value, x.value);
127
+ d.value = n.zoom, c.value = n.pan;
128
+ }
129
+ function ne() {
130
+ P.value = (P.value + 3) % 4, c.value = X(c.value, L.value, x.value, d.value);
131
+ }
132
+ function Le(e) {
133
+ if (e.altKey || e.ctrlKey || e.metaKey) return;
134
+ const n = {
135
+ ArrowLeft: () => Y(-1),
136
+ ArrowRight: () => Y(1),
137
+ "+": () => R(1),
138
+ "=": () => R(1),
139
+ "-": () => R(-1),
140
+ _: () => R(-1),
141
+ 0: U,
142
+ r: ne,
143
+ R: ne
144
+ }[e.key];
145
+ n && (e.preventDefault(), n());
146
+ }
147
+ const le = (e) => {
148
+ const t = O.value?.getBoundingClientRect();
149
+ return { x: e.clientX - (t ? t.left + t.width / 2 : 0), y: e.clientY - (t ? t.top + t.height / 2 : 0) };
150
+ }, _ = /* @__PURE__ */ new Map();
151
+ let Z = !1, pe = 0, N = { x: 0, y: 0 }, j = null;
152
+ const fe = () => {
153
+ const [e, t] = [..._.values()];
154
+ return { x: (e.x + t.x) / 2, y: (e.y + t.y) / 2 };
155
+ }, ge = () => {
156
+ const [e, t] = [..._.values()];
157
+ return Math.hypot(e.x - t.x, e.y - t.y);
158
+ };
159
+ function Se(e) {
160
+ e.pointerType === "mouse" && e.button !== 0 || (O.value?.setPointerCapture?.(e.pointerId), _.set(e.pointerId, { x: e.clientX, y: e.clientY }), ie.value = !0, _.size === 1 ? (Z = !1, pe = Date.now(), N = { x: 0, y: 0 }) : Z = !0);
161
+ }
162
+ function Ie(e) {
163
+ const t = _.get(e.pointerId);
164
+ if (!t) return;
165
+ const n = { x: e.clientX, y: e.clientY };
166
+ if (_.size === 2) {
167
+ const [G, J] = [ge(), fe()];
168
+ _.set(e.pointerId, n);
169
+ const S = fe();
170
+ q(d.value * (ge() / (G || 1)), le({ clientX: S.x, clientY: S.y })), c.value = X({ x: c.value.x + S.x - J.x, y: c.value.y + S.y - J.y }, L.value, x.value, d.value);
171
+ return;
172
+ }
173
+ _.set(e.pointerId, n);
174
+ const f = { x: n.x - t.x, y: n.y - t.y };
175
+ N = { x: N.x + f.x, y: N.y + f.y }, !(!Z && Math.hypot(N.x, N.y) < Pt) && (Z = !0, A.value ? c.value = X({ x: c.value.x + f.x, y: c.value.y + f.y }, L.value, x.value, d.value) : b.value = (b.value + f.x) * (b.value + f.x < 0 && !ve.value || b.value + f.x > 0 && !he.value ? 0.6 : 1));
176
+ }
177
+ function we(e, t = !1) {
178
+ if (!_.delete(e.pointerId) || _.size > 0) return;
179
+ ie.value = !1;
180
+ const n = le(e);
181
+ if (!Z && !t) {
182
+ const S = j && Date.now() - j.at < Ct && Math.hypot(n.x - j.point.x, n.y - j.point.y) < 32;
183
+ j = S ? null : { at: Date.now(), point: n }, S && (A.value ? U() : q(2, n));
184
+ return;
185
+ }
186
+ const f = Date.now() - pe < 250 && Math.abs(b.value) > 30, G = Math.abs(b.value) > Math.max(50, x.value.width * 0.15), J = b.value;
187
+ b.value = 0, !t && !A.value && (G || f) && Y(J < 0 ? 1 : -1);
188
+ }
189
+ function Be(e) {
190
+ const t = e.deltaMode === 1 ? 16 : 1;
191
+ q(d.value * Math.exp(-e.deltaY * t * (e.ctrlKey ? 0.01 : 15e-4)), le(e));
192
+ }
193
+ const De = { width: 120, height: 80 }, y = g(() => de.value ? at(L.value, x.value, d.value, c.value, De) : null);
194
+ function xe(e) {
195
+ if (e.type === "pointermove" && e.buttons === 0) return;
196
+ const t = e.currentTarget.getBoundingClientRect();
197
+ t.width === 0 || t.height === 0 || (c.value = it({ x: (e.clientX - t.left) / t.width, y: (e.clientY - t.top) / t.height }, L.value, x.value, d.value));
198
+ }
199
+ const Ae = g(() => {
200
+ if (!y.value) return {};
201
+ const { width: e, height: t } = P.value % 2 === 0 ? y.value.image : { width: y.value.image.height, height: y.value.image.width };
202
+ return { width: `${e}px`, height: `${t}px`, marginLeft: `${-e / 2}px`, marginTop: `${-t / 2}px`, transform: `rotate(${P.value * 90}deg)` };
203
+ });
204
+ Ye(() => {
205
+ K.value && F();
206
+ });
207
+ const Re = g(() => i.title ?? u("core.viewer.label"));
208
+ return (e, t) => (h(), Ze(je, { to: "body" }, [
209
+ ae.value ? (h(), m("div", ot, [
210
+ C(Ee, {
211
+ appear: "",
212
+ "enter-active-class": "transition-opacity duration-motion-normal ease-motion-standard",
213
+ "enter-from-class": "opacity-0",
214
+ "leave-active-class": "pointer-events-none transition-opacity duration-motion-normal ease-motion-standard",
215
+ "leave-to-class": "opacity-0",
216
+ onAfterLeave: Pe
217
+ }, {
218
+ default: Ke(() => [
219
+ s(K) ? (h(), m("div", {
220
+ key: 0,
221
+ ref_key: "panel",
222
+ ref: T,
223
+ role: "dialog",
224
+ "aria-modal": "true",
225
+ "aria-label": Re.value,
226
+ tabindex: "-1",
227
+ "data-part": "panel",
228
+ "data-test": "photo-viewer",
229
+ class: "fixed inset-0 flex flex-col bg-[#0b1210] text-[#f1f5f3] outline-none",
230
+ onKeydown: Le
231
+ }, [
232
+ p("div", lt, [
233
+ p("h2", st, [
234
+ i.title ? (h(), m("span", rt, ee(i.title), 1)) : w("", !0),
235
+ i.title ? (h(), m("span", ut, " · ")) : w("", !0),
236
+ p("span", ct, ee(s(u)("core.viewer.counter", { current: o.value + 1, total: i.items.length })), 1)
237
+ ]),
238
+ t[6] || (t[6] = p("div", { class: "grow" }, null, -1)),
239
+ v.value && !s($) ? be(e.$slots, "actions", {
240
+ item: v.value,
241
+ index: o.value
242
+ }, void 0, void 0, 0) : w("", !0),
243
+ p("button", {
244
+ type: "button",
245
+ class: M([B, "compact:hidden"]),
246
+ "aria-label": s(u)("core.viewer.zoom_out"),
247
+ "aria-disabled": !A.value,
248
+ "data-test": "zoom-out",
249
+ onClick: t[0] || (t[0] = (n) => R(-1))
250
+ }, [
251
+ C(s(I), {
252
+ name: "zoomOut",
253
+ size: 18
254
+ })
255
+ ], 10, dt),
256
+ p("p", ht, ee(s(u)("core.viewer.zoom_percent", { percent: Ce.value })), 1),
257
+ p("button", {
258
+ type: "button",
259
+ class: M([B, "compact:hidden"]),
260
+ "aria-label": s(u)("core.viewer.zoom_in"),
261
+ "aria-disabled": d.value >= s(ue),
262
+ "data-test": "zoom-in",
263
+ onClick: t[1] || (t[1] = (n) => R(1))
264
+ }, [
265
+ C(s(I), {
266
+ name: "zoomIn",
267
+ size: 18
268
+ })
269
+ ], 10, vt),
270
+ p("button", {
271
+ type: "button",
272
+ class: M(B),
273
+ "aria-label": s(u)("core.viewer.rotate"),
274
+ "data-test": "rotate",
275
+ onClick: ne
276
+ }, [
277
+ C(s(I), {
278
+ name: "rotateCounterclockwise",
279
+ size: 18
280
+ })
281
+ ], 8, mt),
282
+ v.value ? (h(), m("a", {
283
+ key: 1,
284
+ href: v.value.src,
285
+ download: v.value.downloadName ?? "",
286
+ target: "_blank",
287
+ rel: "noopener",
288
+ class: M(B),
289
+ "aria-label": s(u)("core.viewer.download"),
290
+ "data-test": "download"
291
+ }, [
292
+ C(s(I), {
293
+ name: "download",
294
+ size: 18
295
+ })
296
+ ], 8, pt)) : w("", !0),
297
+ p("button", {
298
+ type: "button",
299
+ class: M([B, "bg-white/16"]),
300
+ "aria-label": s(u)("core.actions.close"),
301
+ "data-test": "close",
302
+ onClick: me
303
+ }, [
304
+ C(s(I), {
305
+ name: "close",
306
+ size: 18
307
+ })
308
+ ], 10, ft)
309
+ ]),
310
+ p("div", gt, [
311
+ i.items.length > 1 ? (h(), m("button", {
312
+ key: 0,
313
+ type: "button",
314
+ class: M([B, "size-12 compact:hidden"]),
315
+ "aria-label": s(u)("core.viewer.previous"),
316
+ "aria-disabled": !he.value,
317
+ "data-test": "previous",
318
+ onClick: t[2] || (t[2] = (n) => Y(-1))
319
+ }, [
320
+ C(s(I), {
321
+ name: "arrowLeftSLine",
322
+ size: 22
323
+ })
324
+ ], 10, wt)) : w("", !0),
325
+ p("div", {
326
+ ref_key: "stage",
327
+ ref: x,
328
+ "data-test": "photo-stage",
329
+ class: M(["relative h-full min-w-0 grow touch-none overflow-hidden rounded-md select-none", A.value ? "cursor-grab active:cursor-grabbing" : ""]),
330
+ onPointerdown: Se,
331
+ onPointermove: Ie,
332
+ onPointerup: t[3] || (t[3] = (n) => we(n)),
333
+ onPointercancel: t[4] || (t[4] = (n) => we(n, !0)),
334
+ onWheel: re(Be, ["prevent"])
335
+ }, [
336
+ v.value ? (h(), m("img", {
337
+ key: v.value.src,
338
+ ref: "image",
339
+ src: v.value.src,
340
+ alt: v.value.alt,
341
+ draggable: "false",
342
+ "data-test": "photo",
343
+ class: M(["absolute top-1/2 left-1/2 max-w-none", [de.value ? "" : "opacity-0", ie.value ? "" : "transition-transform duration-motion-normal ease-motion-standard", V.value === "back" ? "animate-step-back" : V.value === "forward" ? "animate-step-in" : ""]]),
344
+ style: te(Te.value),
345
+ onLoad: oe
346
+ }, null, 46, xt)) : w("", !0),
347
+ A.value && y.value ? (h(), m("div", {
348
+ key: 1,
349
+ "data-test": "mini-map",
350
+ class: "absolute right-3.5 bottom-3.5 overflow-hidden rounded-md bg-black/50 ring-1 ring-white/20",
351
+ style: te({ width: `${y.value.image.width}px`, height: `${y.value.image.height}px` }),
352
+ onPointerdown: re(xe, ["stop"]),
353
+ onPointermove: re(xe, ["stop"])
354
+ }, [
355
+ v.value ? (h(), m("img", {
356
+ key: 0,
357
+ src: v.value.thumb ?? v.value.src,
358
+ alt: "",
359
+ draggable: "false",
360
+ class: "pointer-events-none absolute top-1/2 left-1/2 max-w-none opacity-80",
361
+ style: te(Ae.value)
362
+ }, null, 12, yt)) : w("", !0),
363
+ p("span", {
364
+ class: "pointer-events-none absolute rounded-xs ring-2 ring-[#6ee7b7]",
365
+ "data-test": "mini-map-view",
366
+ style: te({ left: `${y.value.view.x}px`, top: `${y.value.view.y}px`, width: `${y.value.view.width}px`, height: `${y.value.view.height}px` })
367
+ }, null, 4)
368
+ ], 36)) : w("", !0)
369
+ ], 34),
370
+ i.items.length > 1 ? (h(), m("button", {
371
+ key: 1,
372
+ type: "button",
373
+ class: M([B, "size-12 compact:hidden"]),
374
+ "aria-label": s(u)("core.viewer.next"),
375
+ "aria-disabled": !ve.value,
376
+ "data-test": "next",
377
+ onClick: t[5] || (t[5] = (n) => Y(1))
378
+ }, [
379
+ C(s(I), {
380
+ name: "arrowRightSLine",
381
+ size: 22
382
+ })
383
+ ], 10, bt)) : w("", !0)
384
+ ]),
385
+ s($) && v.value && e.$slots.actions ? (h(), m("div", _t, [
386
+ be(e.$slots, "actions", {
387
+ item: v.value,
388
+ index: o.value
389
+ })
390
+ ])) : w("", !0),
391
+ i.items.length > 1 ? (h(), m("ul", {
392
+ key: 1,
393
+ ref_key: "strip",
394
+ ref: ce,
395
+ "data-test": "photo-strip",
396
+ class: "flex shrink-0 justify-start gap-2 overflow-x-auto px-4 pt-4 pb-[max(1.25rem,var(--app-safe-bottom))] scrollbar-hide md:justify-center md:px-4.5"
397
+ }, [
398
+ (h(!0), m(We, null, Ue(i.items, (n, f) => (h(), m("li", {
399
+ key: n.src,
400
+ class: "shrink-0"
401
+ }, [
402
+ p("button", {
403
+ type: "button",
404
+ "aria-label": n.alt,
405
+ "aria-current": f === o.value ? "true" : void 0,
406
+ "data-test": "thumbnail",
407
+ class: M(["block h-11 w-16 cursor-pointer overflow-hidden rounded-[5px] bg-[#2a3431] transition-opacity duration-motion-fast focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#6ee7b7]", f === o.value ? "ring-2 ring-[#6ee7b7]" : "opacity-60 hover:opacity-100"]),
408
+ onClick: (G) => {
409
+ V.value = f > o.value ? "forward" : "back", o.value = f;
410
+ }
411
+ }, [
412
+ p("img", {
413
+ src: n.thumb ?? n.src,
414
+ alt: "",
415
+ loading: "lazy",
416
+ draggable: "false",
417
+ class: "size-full object-cover"
418
+ }, null, 8, Mt)
419
+ ], 10, kt)
420
+ ]))), 128))
421
+ ], 512)) : (h(), m("div", zt)),
422
+ p("span", $t, ee(v.value?.alt), 1)
423
+ ], 40, nt)) : w("", !0)
424
+ ]),
425
+ _: 3
426
+ })
427
+ ])) : w("", !0)
428
+ ]));
429
+ }
430
+ });
431
+ export {
432
+ Bt as _
433
+ };
@@ -1,10 +1,10 @@
1
1
  import { defineComponent as A, watch as X, openBlock as v, createBlock as S, unref as e, withCtx as u, createVNode as r, mergeProps as E, useModel as pe, useId as fe, useTemplateRef as J, ref as w, onMounted as me, onBeforeUnmount as ve, computed as M, createElementBlock as I, withModifiers as _e, toDisplayString as b, createCommentVNode as W, createElementVNode as x, createTextVNode as N, Fragment as le, mergeModels as oe } from "vue";
2
2
  import { useI18n as R } from "vue-i18n";
3
3
  import { a as ge } from "./AdaptivePageShell.vue_vue_type_script_setup_true_lang-CxU9aNRQ.js";
4
- import { u as L } from "./platform-q3cjODLx.js";
4
+ import { u as L } from "./platform-PZpUkkMS.js";
5
5
  import { _ as Q } from "./AsyncSection.vue_vue_type_script_setup_true_lang-Blj6KgCr.js";
6
6
  import { u as Y } from "./useLoad-M7V-AVwR.js";
7
- import { i as k, d as G } from "./index-BmowiT1y.js";
7
+ import { i as k, d as G } from "./index-BVU76sBO.js";
8
8
  import { u as Z } from "./FormErrors.vue_vue_type_script_setup_true_lang-DGOSc-PS.js";
9
9
  import { _ as ee } from "./FormView.vue_vue_type_script_setup_true_lang-BUrYkjmF.js";
10
10
  import { _ as U } from "./TextField.vue_vue_type_script_setup_true_lang-CP2WeU36.js";
@@ -9,12 +9,12 @@ import { u as ae } from "./useSaveChrome-7huA3FzR.js";
9
9
  import { t as oe } from "./toast-CqSDTWRX.js";
10
10
  import { _ as S } from "./Badge.vue_vue_type_script_setup_true_lang-DJyZc0C7.js";
11
11
  import { _ as E } from "./Banner.vue_vue_type_script_setup_true_lang-DSStj_5z.js";
12
- import { d as G, u as J, p as ne, o as R, r as D, g as H, s as le, e as re, a as ie, f as ce, b as ue, h as de } from "./index-Yy28omu6.js";
12
+ import { d as G, u as J, p as ne, o as R, r as D, g as H, s as le, e as re, a as ie, f as ce, b as ue, h as de } from "./index-CvJSAsfk.js";
13
13
  import { _ as me } from "./Button.vue_vue_type_script_setup_true_lang-CL9Qh5yq.js";
14
14
  import { _ as fe } from "./Tabs.vue_vue_type_script_setup_true_lang-CcMcE38r.js";
15
15
  import { _ as pe } from "./SegmentedField.vue_vue_type_script_setup_true_lang-Dg-_ZjgR.js";
16
16
  import { _ as _e } from "./SwitchField.vue_vue_type_script_setup_true_lang-ALvJisiP.js";
17
- import { u as ge } from "./platform-q3cjODLx.js";
17
+ import { u as ge } from "./platform-PZpUkkMS.js";
18
18
  const ve = {
19
19
  class: "flex min-w-0 flex-col gap-4 lg:grid lg:grid-cols-[15rem_minmax(0,1fr)] lg:items-start lg:gap-8",
20
20
  "data-test": "permission-tree"
@@ -8,16 +8,16 @@ import { u as Z } from "./describeError-B-NMa--w.js";
8
8
  import { _ as ee } from "./AlertDialog.vue_vue_type_script_setup_true_lang-whA4WLdl.js";
9
9
  import { t as q } from "./toast-CqSDTWRX.js";
10
10
  import { _ as oe } from "./RecordHeader.vue_vue_type_script_setup_true_lang-szzWzdDu.js";
11
- import { u as te } from "./platform-q3cjODLx.js";
11
+ import { u as te } from "./platform-PZpUkkMS.js";
12
12
  import { a as ae, u as le } from "./routeResource-DlTsGTg_.js";
13
13
  import { a as se } from "./ResourcePage.vue_vue_type_script_setup_true_lang-BFaaFQSm.js";
14
14
  import { _ as re } from "./AsyncSection.vue_vue_type_script_setup_true_lang-Blj6KgCr.js";
15
15
  import { _ as H } from "./Badge.vue_vue_type_script_setup_true_lang-DJyZc0C7.js";
16
- import { u as O, a as U, f as ce, d as ne, b as M, c as T } from "./index-Yy28omu6.js";
16
+ import { u as O, a as U, f as ce, d as ne, b as M, c as T } from "./index-CvJSAsfk.js";
17
17
  import { _ as J } from "./SelectField.vue_vue_type_script_setup_true_lang-C3FbRQW7.js";
18
18
  import { u as ie, _ as ue } from "./useCommand-Cj-APj-P.js";
19
19
  import { _ as me } from "./Modal.vue_vue_type_script_setup_true_lang-DpBb8ans.js";
20
- import { _ as pe } from "./RoleEditor.vue_vue_type_script_setup_true_lang-B6g2760V.js";
20
+ import { _ as pe } from "./RoleEditor.vue_vue_type_script_setup_true_lang-Hr0WgL1K.js";
21
21
  const de = { "data-test": "role-replace" }, fe = /* @__PURE__ */ I({
22
22
  __name: "ReplaceRoleDialog",
23
23
  props: {
@@ -7,11 +7,11 @@ import { _ as U } from "./FormGroup.vue_vue_type_script_setup_true_lang-DSwSRsA5
7
7
  import { e as j } from "./control-B4SdblL6.js";
8
8
  import { _ as D } from "./TextField.vue_vue_type_script_setup_true_lang-CP2WeU36.js";
9
9
  import { a as I } from "./AdaptivePageShell.vue_vue_type_script_setup_true_lang-CxU9aNRQ.js";
10
- import { u as K } from "./platform-q3cjODLx.js";
10
+ import { u as K } from "./platform-PZpUkkMS.js";
11
11
  import { _ as T } from "./AsyncSection.vue_vue_type_script_setup_true_lang-Blj6KgCr.js";
12
12
  import { _ as q } from "./Badge.vue_vue_type_script_setup_true_lang-DJyZc0C7.js";
13
13
  import { u as z } from "./useLoad-M7V-AVwR.js";
14
- import { u as G, a as H, b as J, c as x } from "./index-Yy28omu6.js";
14
+ import { u as G, a as H, b as J, c as x } from "./index-CvJSAsfk.js";
15
15
  const M = {
16
16
  class: "flex min-w-0 flex-col gap-group-gap",
17
17
  "data-test": "roles-index"
@@ -5,7 +5,7 @@ import { _ as q } from "./IconTile.vue_vue_type_script_setup_true_lang-_FXvaj93.
5
5
  import { _ as G } from "./Icon.vue_vue_type_script_lang-D7oC-d-S.js";
6
6
  import { a as re } from "./mediaQuery-CygcXmFW.js";
7
7
  import { u as ie } from "./access-DmAceEo5.js";
8
- import { u as ce, a as ue } from "./sections-D-kD98vu.js";
8
+ import { u as ce, a as ue } from "./sections-CeZl-Jxg.js";
9
9
  import { p as de } from "./AdaptivePageShell.vue_vue_type_script_setup_true_lang-CxU9aNRQ.js";
10
10
  import { p as me } from "./sectionIndex-BS0ic5W7.js";
11
11
  import { _ as K, a as pe } from "./SectionList.vue_vue_type_script_setup_true_lang-BJnz2ROc.js";