@wssto2/vue-core 0.1.0 → 0.2.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.
Files changed (95) hide show
  1. package/README.md +20 -9
  2. package/dist/{AdaptivePageShell.vue_vue_type_script_setup_true_lang-CKghARkW.js → AdaptivePageShell.vue_vue_type_script_setup_true_lang-CeKK8_g5.js} +2 -2
  3. package/dist/{AlertDialog.vue_vue_type_script_setup_true_lang-BZb4qKXo.js → AlertDialog.vue_vue_type_script_setup_true_lang-e4hzkzg3.js} +1 -1
  4. package/dist/{AsyncSection.vue_vue_type_script_setup_true_lang-B82bl36A.js → AsyncSection.vue_vue_type_script_setup_true_lang-CWLB3xsR.js} +1 -1
  5. package/dist/Badge.vue_vue_type_script_setup_true_lang-DJyZc0C7.js +51 -0
  6. package/dist/Button.vue_vue_type_script_setup_true_lang-B1eZgLae.js +182 -0
  7. package/dist/CountryFlag.vue_vue_type_script_setup_true_lang-Kry_vPPZ.js +299 -0
  8. package/dist/{DiscardChangesModal.vue_vue_type_script_setup_true_lang-Bx5O1RZJ.js → DiscardChangesModal.vue_vue_type_script_setup_true_lang-DyhYHRyz.js} +1 -1
  9. package/dist/{LeaveGuardRoot.vue_vue_type_script_setup_true_lang-DH6EB8br.js → LeaveGuardRoot.vue_vue_type_script_setup_true_lang-CvwoT1JF.js} +1 -1
  10. package/dist/{Menu.vue_vue_type_script_setup_true_lang-D44EHXQZ.js → Menu.vue_vue_type_script_setup_true_lang-CrMj6KPD.js} +1 -1
  11. package/dist/{Modal.vue_vue_type_script_setup_true_lang-DYQgaUtj.js → Modal.vue_vue_type_script_setup_true_lang-BQZM49gC.js} +138 -128
  12. package/dist/{PhotoViewer.vue_vue_type_script_setup_true_lang-DDVQXJRB.js → PhotoViewer.vue_vue_type_script_setup_true_lang-ElDizaW2.js} +1 -1
  13. package/dist/{SectionList.vue_vue_type_script_setup_true_lang-DGcKX_OJ.js → SectionList.vue_vue_type_script_setup_true_lang-L9ita_Kx.js} +2 -2
  14. package/dist/SelectField.vue_vue_type_script_setup_true_lang-DZTrU8NJ.js +661 -0
  15. package/dist/{Sheet.vue_vue_type_script_setup_true_lang-BLBD5ps8.js → Sheet.vue_vue_type_script_setup_true_lang-CtkJ-4e3.js} +1 -1
  16. package/dist/{Tooltip.vue_vue_type_script_setup_true_lang-BJWPVyfT.js → Tooltip.vue_vue_type_script_setup_true_lang-OOD_XNWx.js} +1 -1
  17. package/dist/app/application.d.ts +5 -0
  18. package/dist/app/environment.d.ts +2 -0
  19. package/dist/app/index.js +75 -72
  20. package/dist/button/index.d.ts +1 -1
  21. package/dist/button/index.js +5 -3
  22. package/dist/button/shortcut.d.ts +28 -2
  23. package/dist/collection/CollectionPage.vue.d.ts +1 -0
  24. package/dist/collection/CollectionRows.vue.d.ts +59 -0
  25. package/dist/collection/CollectionTable.vue.d.ts +1 -1
  26. package/dist/collection/DataTable.vue.d.ts +47 -0
  27. package/dist/collection/RowActions.vue.d.ts +19 -0
  28. package/dist/collection/columns.d.ts +2 -0
  29. package/dist/collection/index.d.ts +4 -2
  30. package/dist/collection/index.js +1752 -1610
  31. package/dist/collection/rowLayout.d.ts +10 -0
  32. package/dist/collection/slots.d.ts +6 -3
  33. package/dist/describeError-l5T9b8Uv.js +41 -0
  34. package/dist/dialogStack-DZZg55w0.js +31 -0
  35. package/dist/form/CommandDialog.vue.d.ts +12 -1
  36. package/dist/form/FormGroup.vue.d.ts +1 -1
  37. package/dist/form/MultiSelectField.vue.d.ts +4 -1
  38. package/dist/form/NumberField.vue.d.ts +6 -0
  39. package/dist/form/OptionList.vue.d.ts +6 -2
  40. package/dist/form/SelectField.vue.d.ts +4 -1
  41. package/dist/form/index.d.ts +2 -0
  42. package/dist/form/index.js +1940 -2008
  43. package/dist/form/suggestions.d.ts +11 -0
  44. package/dist/form/useOptions.d.ts +60 -0
  45. package/dist/i18n/describeError.d.ts +31 -0
  46. package/dist/i18n/index.d.ts +26 -0
  47. package/dist/i18n/index.js +22 -20
  48. package/dist/index.d.ts +1 -1
  49. package/dist/index.js +1 -1
  50. package/dist/internal/CountryFlag.vue.d.ts +10 -0
  51. package/dist/modal/Modal.vue.d.ts +4 -0
  52. package/dist/modal/ShortcutHelp.vue.d.ts +2 -0
  53. package/dist/modal/index.d.ts +2 -0
  54. package/dist/modal/index.js +64 -6
  55. package/dist/modal/placement.d.ts +22 -0
  56. package/dist/{options-CjSz2dQK.js → options-DAkBtYkI.js} +3 -3
  57. package/dist/overlay/Popover.vue.d.ts +3 -0
  58. package/dist/overlay/dialogStack.d.ts +9 -0
  59. package/dist/overlay/index.d.ts +1 -1
  60. package/dist/overlay/index.js +18 -17
  61. package/dist/page/index.js +4 -4
  62. package/dist/phone/index.js +247 -540
  63. package/dist/platform/AccessGate.vue.d.ts +50 -0
  64. package/dist/platform/index.d.ts +2 -0
  65. package/dist/platform/index.js +86 -66
  66. package/dist/resource/index.js +42 -42
  67. package/dist/shell/AccountMenuItem.vue.d.ts +3 -0
  68. package/dist/shell/NavigationList.vue.d.ts +1 -1
  69. package/dist/shell/index.js +406 -394
  70. package/dist/state/Badge.vue.d.ts +17 -10
  71. package/dist/state/hue.d.ts +8 -0
  72. package/dist/state/index.d.ts +2 -0
  73. package/dist/state/index.js +92 -56
  74. package/dist/state/useLoad.d.ts +41 -0
  75. package/dist/styles.css +1 -1
  76. package/dist/testing/app.d.ts +61 -0
  77. package/dist/testing/async.d.ts +12 -0
  78. package/dist/testing/collection.d.ts +18 -0
  79. package/dist/testing/format.d.ts +9 -0
  80. package/dist/testing/i18n.d.ts +16 -0
  81. package/dist/testing/index.d.ts +14 -0
  82. package/dist/testing/index.js +178 -0
  83. package/dist/testing/media.d.ts +23 -0
  84. package/dist/testing/platform.d.ts +40 -0
  85. package/dist/testing/transport.d.ts +40 -0
  86. package/dist/{toast-BTeX0r66.js → toast-DvrHQ6Ag.js} +45 -43
  87. package/dist/{useDialog-wmyNx2j_.js → useDialog-CXR3hN0G.js} +1 -1
  88. package/package.json +5 -1
  89. package/src/styles/theme.css +60 -0
  90. package/dist/Badge.vue_vue_type_script_setup_true_lang-DKc6ugmr.js +0 -31
  91. package/dist/Button.vue_vue_type_script_setup_true_lang-3f0emVNU.js +0 -141
  92. package/dist/SelectField.vue_vue_type_script_setup_true_lang-SyFWE33A.js +0 -422
  93. package/dist/dialogStack-DiTG1rZc.js +0 -26
  94. package/dist/phone/CountryFlag.vue.d.ts +0 -10
  95. /package/dist/{phone → internal}/flagLoaders.d.ts +0 -0
@@ -59,6 +59,11 @@ export interface ApplicationLocaleOptions {
59
59
  fallback?: string;
60
60
  /** The locales the application offers. Default: the library's (`en`, `hr`, `bs`, `sl`). */
61
61
  supported?: readonly string[];
62
+ /**
63
+ * The flag shown beside each locale's name in the language menu, as an ISO 3166-1 country code: `{ en: "GB", sl: "SI" }`.
64
+ * A flag stands for a language here, so the app chooses (English is not one country). No entry: the name alone.
65
+ */
66
+ flags?: Readonly<Record<string, string>>;
62
67
  /**
63
68
  * Called after a switch to another locale committed (not for the start locale, a switch to the locale already active, or a
64
69
  * switch a later one superseded), so the application can save the choice on the user. Not awaited: the page has already
@@ -22,6 +22,8 @@ export interface ApplicationEnvironment {
22
22
  /** The active locale. */
23
23
  readonly locale: Readonly<Ref<string>>;
24
24
  readonly locales: readonly string[];
25
+ /** The flag country of each locale that has one (`{ en: "GB" }`); a locale without one shows no flag. */
26
+ readonly localeFlags: Readonly<Record<string, string>>;
25
27
  /** Switches the locale once the texts in use exist in it; see `MessageRuntime.setLocale`. */
26
28
  setLocale(locale: string): Promise<boolean>;
27
29
  /** Tries the start again after a failed one. */
package/dist/app/index.js CHANGED
@@ -1,8 +1,8 @@
1
- var Ee = Object.defineProperty;
2
- var ke = (e, a, n) => a in e ? Ee(e, a, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[a] = n;
3
- var Y = (e, a, n) => ke(e, typeof a != "symbol" ? a + "" : a, n);
4
- import { effectScope as D, watch as P, defineComponent as ue, openBlock as Se, createElementBlock as Le, createVNode as Z, unref as _, withCtx as ee, createTextVNode as xe, toDisplayString as Ae, shallowRef as Me, computed as Re, h as te, createApp as Ne } from "vue";
5
- import { useI18n as je, createI18n as Oe } from "vue-i18n";
1
+ var ke = Object.defineProperty;
2
+ var Ee = (e, a, n) => a in e ? ke(e, a, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[a] = n;
3
+ var Y = (e, a, n) => Ee(e, typeof a != "symbol" ? a + "" : a, n);
4
+ import { effectScope as D, watch as P, defineComponent as ue, openBlock as Se, createElementBlock as Le, createVNode as Z, unref as _, withCtx as ee, createTextVNode as xe, toDisplayString as Ae, shallowRef as Me, computed as Re, h as te, createApp as je } from "vue";
5
+ import { useI18n as Ne, createI18n as Oe } from "vue-i18n";
6
6
  import { createRouter as Te, isNavigationFailure as _e } from "vue-router";
7
7
  import { i as Ce, a as se } from "../environment-D3nozt9a.js";
8
8
  import { b as Ct } from "../environment-D3nozt9a.js";
@@ -16,23 +16,23 @@ import { c as Ue, _ as Xe, i as Ye } from "../NoAccess.vue_vue_type_script_setup
16
16
  import { b as Ze, c as et, n as re } from "../navigation-B33ikiCS.js";
17
17
  import { i as tt, c as st, s as ae } from "../feature-DyDtyMLU.js";
18
18
  import { S as It, d as Ft, p as Wt } from "../feature-DyDtyMLU.js";
19
- import { _ as ot } from "../Button.vue_vue_type_script_setup_true_lang-3f0emVNU.js";
19
+ import { _ as ot } from "../Button.vue_vue_type_script_setup_true_lang-B1eZgLae.js";
20
20
  import { _ as nt } from "../EmptyState.vue_vue_type_script_setup_true_lang-BeGpHMUP.js";
21
21
  function rt(e) {
22
22
  const { platform: a } = e, n = D();
23
23
  let i = null, h = null, y = !1;
24
- function b(l, d) {
24
+ function $(l, d) {
25
25
  const g = new AbortController(), u = { controller: g, stops: [] };
26
26
  for (const p of l)
27
27
  try {
28
- const $ = d(p, g.signal);
29
- typeof $ == "function" && u.stops.push({ owned: p, stop: $ });
30
- } catch ($) {
31
- e.onError($, p);
28
+ const b = d(p, g.signal);
29
+ typeof b == "function" && u.stops.push({ owned: p, stop: b });
30
+ } catch (b) {
31
+ e.onError(b, p);
32
32
  }
33
33
  return u;
34
34
  }
35
- function E(l) {
35
+ function k(l) {
36
36
  if (l) {
37
37
  l.controller.abort();
38
38
  for (const { owned: d, stop: g } of l.stops.reverse())
@@ -43,24 +43,24 @@ function rt(e) {
43
43
  }
44
44
  }
45
45
  }
46
- const k = (l) => e.effects.filter((d) => d.effect.scope === l), x = (l) => l.status !== "authenticated" ? null : e.sessionKey ? e.sessionKey(l) : String(l.user.id);
46
+ const E = (l) => e.effects.filter((d) => d.effect.scope === l), x = (l) => l.status !== "authenticated" ? null : e.sessionKey ? e.sessionKey(l) : String(l.user.id);
47
47
  return {
48
48
  start() {
49
49
  if (y || i) return;
50
- i = b(
51
- k("app"),
50
+ i = $(
51
+ E("app"),
52
52
  (d, g) => d.effect.start({ signal: g, platform: a, report: (u) => e.onError(u, d) })
53
53
  );
54
- const l = k("session");
54
+ const l = E("session");
55
55
  n.run(
56
56
  () => P(
57
57
  () => x(a.session.state.value),
58
58
  (d) => {
59
- E(h), h = null;
59
+ k(h), h = null;
60
60
  const g = a.session.state.value;
61
- d === null || g.status !== "authenticated" || (h = b(
61
+ d === null || g.status !== "authenticated" || (h = $(
62
62
  l,
63
- (u, p) => u.effect.start({ signal: p, platform: a, user: g.user, report: ($) => e.onError($, u) })
63
+ (u, p) => u.effect.start({ signal: p, platform: a, user: g.user, report: (b) => e.onError(b, u) })
64
64
  ));
65
65
  },
66
66
  { immediate: !0, flush: "sync" }
@@ -68,7 +68,7 @@ function rt(e) {
68
68
  );
69
69
  },
70
70
  dispose() {
71
- y || (y = !0, n.stop(), E(h), E(i), h = i = null);
71
+ y || (y = !0, n.stop(), k(h), k(i), h = i = null);
72
72
  }
73
73
  };
74
74
  }
@@ -79,7 +79,7 @@ const at = { class: "mx-auto flex min-h-screen max-w-content items-center justif
79
79
  },
80
80
  emits: ["retry"],
81
81
  setup(e) {
82
- const { t: a } = je();
82
+ const { t: a } = Ne();
83
83
  return (n, i) => (Se(), Le("div", at, [
84
84
  Z(_(nt), {
85
85
  title: _(a)("core.startup.title"),
@@ -130,25 +130,25 @@ function ct(e) {
130
130
  for (const o of i)
131
131
  for (const s of o.requires)
132
132
  h.has(s) || n(w(o), `requires the feature "${s}", which is not in the features list.`);
133
- const y = [], b = /* @__PURE__ */ new Set(), E = (o) => {
134
- if (b.has(o.id)) return;
133
+ const y = [], $ = /* @__PURE__ */ new Set(), k = (o) => {
134
+ if ($.has(o.id)) return;
135
135
  const s = y.indexOf(o.id);
136
136
  if (s !== -1) {
137
- n(w(o), `requirements form a cycle: ${[...y.slice(s), o.id].join(" -> ")}.`), b.add(o.id);
137
+ n(w(o), `requirements form a cycle: ${[...y.slice(s), o.id].join(" -> ")}.`), $.add(o.id);
138
138
  return;
139
139
  }
140
140
  y.push(o.id);
141
141
  for (const c of o.requires) {
142
142
  const m = h.get(c);
143
- m && E(m);
143
+ m && k(m);
144
144
  }
145
- y.pop(), b.add(o.id);
145
+ y.pop(), $.add(o.id);
146
146
  };
147
- i.forEach(E);
148
- const k = new Set(e.platform.config.capabilities);
147
+ i.forEach(k);
148
+ const E = new Set(e.platform.config.capabilities);
149
149
  for (const o of i)
150
150
  for (const s of o.backend)
151
- k.has(s) || n(w(o), `needs the backend capability "${s}", which the server does not report.`);
151
+ E.has(s) || n(w(o), `needs the backend capability "${s}", which the server does not report.`);
152
152
  const x = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map();
153
153
  for (const o of i) {
154
154
  for (const s of o.routes) {
@@ -173,24 +173,24 @@ function ct(e) {
173
173
  for (const c of s) {
174
174
  const m = u.get(c.namespace);
175
175
  m ? n(o, `declares the message namespace "${c.namespace}", which ${m} declares too.`) : u.set(c.namespace, o);
176
- for (const N of Object.keys(c.loaders))
177
- e.supportedLocales.includes(N) || n(o, `the namespace "${c.namespace}" has a loader for "${N}", which is not a supported locale (${e.supportedLocales.join(", ")}).`);
176
+ for (const j of Object.keys(c.loaders))
177
+ e.supportedLocales.includes(j) || n(o, `the namespace "${c.namespace}" has a loader for "${j}", which is not a supported locale (${e.supportedLocales.join(", ")}).`);
178
178
  }
179
179
  };
180
180
  for (const o of i) p(w(o), o.messages);
181
181
  p(ce, e.messages);
182
- const $ = (o) => u.has(o);
182
+ const b = (o) => u.has(o);
183
183
  for (const o of i)
184
184
  for (const { record: s } of B(o.routes))
185
185
  for (const c of s.meta?.messages ?? [])
186
- $(c) || n(w(o), `the route "${String(s.name ?? s.path)}" needs the message namespace "${c}", which nobody declares.`);
186
+ b(c) || n(w(o), `the route "${String(s.name ?? s.path)}" needs the message namespace "${c}", which nobody declares.`);
187
187
  const A = /* @__PURE__ */ new Map();
188
188
  for (const o of i)
189
189
  for (const s of o.contributions) {
190
190
  const c = A.get(s.id);
191
191
  c ? n(w(o), `declares the shell contribution "${s.id}", which feature "${c.id}" declares too.`) : A.set(s.id, o), e.shellSlots && !s.optional && !e.shellSlots.includes(s.slot) && n(w(o), `contributes "${s.id}" to the slot "${s.slot}", which the shell does not render (it renders ${e.shellSlots.join(", ") || "none"}). Mark it optional to leave it out instead.`);
192
192
  for (const m of s.messages ?? [])
193
- $(m) || n(w(o), `the contribution "${s.id}" needs the message namespace "${m}", which nobody declares.`);
193
+ b(m) || n(w(o), `the contribution "${s.id}" needs the message namespace "${m}", which nobody declares.`);
194
194
  }
195
195
  const R = /* @__PURE__ */ new Map();
196
196
  for (const o of i)
@@ -218,30 +218,32 @@ function fe(e, a) {
218
218
  }));
219
219
  }
220
220
  const le = (e) => [...new Set(e)];
221
- function jt(e) {
221
+ function Nt(e) {
222
222
  const { platform: a } = e, n = e.locale?.supported ?? Object.keys(oe), i = e.locale?.fallback ?? "en", h = e.shell === void 0 ? void 0 : ut(e.shell) ? e.shell : { component: e.shell, slots: void 0, progress: void 0 }, y = [];
223
223
  n.includes(i) || y.push({ owner: "application", message: `the fallback locale "${i}" is not among the supported locales (${n.join(", ")}).` });
224
- const b = e.locale?.initial ?? (n.includes(a.config.locale) ? a.config.locale : i);
225
- n.includes(b) || y.push({ owner: "application", message: `the initial locale "${b}" is not among the supported locales (${n.join(", ")}).` });
226
- const E = [Je, Fe, He, Ve, De, re, ae, ne, se], k = ct({
224
+ for (const t of Object.keys(e.locale?.flags ?? {}))
225
+ n.includes(t) || y.push({ owner: "application", message: `locale.flags names the locale "${t}", which is not among the supported locales (${n.join(", ")}).` });
226
+ const $ = e.locale?.initial ?? (n.includes(a.config.locale) ? a.config.locale : i);
227
+ n.includes($) || y.push({ owner: "application", message: `the initial locale "${$}" is not among the supported locales (${n.join(", ")}).` });
228
+ const k = [Je, Fe, He, Ve, De, re, ae, ne, se], E = ct({
227
229
  features: e.features,
228
230
  platform: a,
229
231
  messages: e.messages ?? [],
230
- reservedContexts: E,
232
+ reservedContexts: k,
231
233
  supportedLocales: n,
232
234
  shellSlots: h?.slots
233
- }), x = [...y, ...k.issues], l = k.features, d = Ze(
235
+ }), x = [...y, ...E.issues], l = E.features, d = Ze(
234
236
  l.flatMap((t) => t.navigation.map((r) => ({ feature: t.id, binding: r }))),
235
237
  e.navigation
236
238
  );
237
239
  for (const t of d.issues) x.push({ owner: "navigation", message: t });
238
240
  if (x.length > 0) throw new ie(x);
239
- const g = lt(b, i, e.i18n), u = g.global;
241
+ const g = lt($, i, e.i18n), u = g.global;
240
242
  for (const [t, r] of Object.entries(oe)) u.mergeLocaleMessage(t, r);
241
243
  for (const [t, r] of Object.entries(e.i18n?.messages ?? {})) u.mergeLocaleMessage(t, r);
242
- const p = Ke({ locale: () => u.locale.value, formatters: e.formatting }), $ = [...l.flatMap((t) => t.messages), ...e.messages ?? []], A = (t) => (e.onError ?? ft)({ ...t, route: s.currentRoute.value.matched.length > 0 ? s.currentRoute.value.fullPath : null }), R = We({
244
+ const p = Ke({ locale: () => u.locale.value, formatters: e.formatting }), b = [...l.flatMap((t) => t.messages), ...e.messages ?? []], A = (t) => (e.onError ?? ft)({ ...t, route: s.currentRoute.value.matched.length > 0 ? s.currentRoute.value.fullPath : null }), R = We({
243
245
  target: u,
244
- namespaces: $,
246
+ namespaces: b,
245
247
  fallback: i,
246
248
  supported: n,
247
249
  onFailure: (t) => A({ source: "messages", error: t.error, detail: `${t.namespace} (${t.locale})`, feature: o.get(t.namespace) })
@@ -249,7 +251,7 @@ function jt(e) {
249
251
  history: e.router?.history ?? Ue(),
250
252
  routes: l.flatMap((t) => fe(t.routes, t.id)),
251
253
  scrollBehavior: e.router?.scrollBehavior ?? ((t, r) => t.name === r.name ? !1 : { top: 0 })
252
- }), c = e.router?.login ?? { name: "login" }, m = e.router?.home ?? { path: "/" }, N = [], H = (t) => {
254
+ }), c = e.router?.login ?? { name: "login" }, m = e.router?.home ?? { path: "/" }, j = [], H = (t) => {
253
255
  try {
254
256
  return s.resolve(t).matched.length > 0 ? null : "matches no route";
255
257
  } catch (r) {
@@ -259,17 +261,18 @@ function jt(e) {
259
261
  };
260
262
  if (l.some((t) => t.routes.some((r) => r.meta?.public !== !0))) {
261
263
  const t = H(c) ?? (s.resolve(c).meta.public === !0 ? null : "is not public (meta.public: true)");
262
- t && N.push({ owner: "application", message: `the login route ${JSON.stringify(c)} ${t.replace("matches no route", "does not exist")}, but protected routes are installed: an anonymous visitor would have nowhere to go. Install a feature with the login route or set router.login.` });
264
+ t && j.push({ owner: "application", message: `the login route ${JSON.stringify(c)} ${t.replace("matches no route", "does not exist")}, but protected routes are installed: an anonymous visitor would have nowhere to go. Install a feature with the login route or set router.login.` });
263
265
  }
264
266
  for (const { feature: t, binding: r } of d.destinations.values()) {
265
267
  const f = H(r.to);
266
- f && N.push({ owner: `feature "${t}"`, message: `the destination "${r.destination}" is bound to ${JSON.stringify(r.to)}, which ${f}.` });
268
+ f && j.push({ owner: `feature "${t}"`, message: `the destination "${r.destination}" is bound to ${JSON.stringify(r.to)}, which ${f}.` });
267
269
  }
268
- if (N.length > 0) throw new ie(N);
269
- const j = Me({ status: "idle" }), K = {
270
- state: j,
270
+ if (j.length > 0) throw new ie(j);
271
+ const N = Me({ status: "idle" }), K = {
272
+ state: N,
271
273
  locale: Re(() => u.locale.value),
272
274
  locales: n,
275
+ localeFlags: e.locale?.flags ?? {},
273
276
  setLocale: async (t) => {
274
277
  const r = u.locale.value, f = await R.setLocale(t);
275
278
  if (f && u.locale.value !== r) {
@@ -305,19 +308,19 @@ function jt(e) {
305
308
  name: "ApplicationRoot",
306
309
  setup() {
307
310
  return () => {
308
- const t = j.value;
311
+ const t = N.value;
309
312
  return t.status === "failed" ? te(it, { kind: t.kind, onRetry: () => void q() }) : t.status !== "ready" ? null : te(h?.component ?? Qe);
310
313
  };
311
314
  }
312
- }), v = Ne(ye);
315
+ }), v = je(ye);
313
316
  Ge(v, a), v.use(g), Ie(v, p), F = Pe(v), Be(v), Ce(v), e.icons && qe(v, ...Array.isArray(e.icons) ? e.icons : [e.icons]), v.provide(se, K), v.provide(re, ge), v.provide(ae, ve), v.provide(ne, we);
314
317
  for (const t of l) for (const { key: r, value: f } of t.contexts) v.provide(r, f);
315
318
  let M = !1, J = !1, z = !1, Q = !1;
316
319
  const T = [];
317
- function be() {
320
+ function $e() {
318
321
  const t = v.config.errorHandler;
319
- v.config.errorHandler = (L, $e, X) => {
320
- A({ source: "vue", error: L, detail: X }), t?.(L, $e, X);
322
+ v.config.errorHandler = (L, be, X) => {
323
+ A({ source: "vue", error: L, detail: X }), t?.(L, be, X);
321
324
  };
322
325
  const r = (L) => A({ source: "unhandledrejection", error: L.reason }), f = (L) => {
323
326
  L.error && A({ source: "window", error: L.error });
@@ -350,10 +353,10 @@ function jt(e) {
350
353
  ), T.push(() => O.stop());
351
354
  }
352
355
  const C = (t, r) => {
353
- j.value = { status: "failed", kind: t, error: r };
356
+ N.value = { status: "failed", kind: t, error: r };
354
357
  };
355
358
  async function U() {
356
- j.value = { status: "starting" };
359
+ N.value = { status: "starting" };
357
360
  const t = await a.session.restore();
358
361
  if (M) return;
359
362
  if (t.status === "failed") return C("session", t.error);
@@ -368,23 +371,23 @@ function jt(e) {
368
371
  M || C("startup", f);
369
372
  return;
370
373
  }
371
- Q || (v.use(s), Q = !0), j.value = { status: "ready" }, V.start();
374
+ Q || (v.use(s), Q = !0), N.value = { status: "ready" }, V.start();
372
375
  }
373
376
  }
374
377
  async function q() {
375
- M || j.value.status !== "failed" || (await R.retry(), await U());
378
+ M || N.value.status !== "failed" || (await R.retry(), await U());
376
379
  }
377
380
  return {
378
381
  app: v,
379
382
  router: s,
380
383
  i18n: g,
381
- state: j,
384
+ state: N,
382
385
  locale: K.locale,
383
386
  setLocale: K.setLocale,
384
387
  async mount(t) {
385
388
  if (M) throw new Error("This application was disposed; create a new one with createApplication().");
386
389
  if (J) throw new Error("This application is already mounted.");
387
- J = !0, be(), await U(), !M && (v.mount(t), z = !0);
390
+ J = !0, $e(), await U(), !M && (v.mount(t), z = !0);
388
391
  },
389
392
  retry: q,
390
393
  dispose() {
@@ -409,31 +412,31 @@ function Ot(e = {}) {
409
412
  id: "vue-core.keep-session-alive",
410
413
  scope: "session",
411
414
  start({ signal: i, platform: h, report: y }) {
412
- let b, E = null;
413
- const k = () => {
415
+ let $, k = null;
416
+ const E = () => {
414
417
  const p = h.session.state.value;
415
418
  return p.status === "authenticated" && p.expiresAt ? p.expiresAt.getTime() - Date.now() - a : null;
416
- }, x = () => (E ?? (E = (async () => {
419
+ }, x = () => (k ?? (k = (async () => {
417
420
  try {
418
421
  await e.renew?.(h), await h.session.refresh();
419
422
  } catch (p) {
420
423
  y(p);
421
424
  } finally {
422
- E = null;
425
+ k = null;
423
426
  }
424
- })()), E);
427
+ })()), k);
425
428
  function l(p = 0) {
426
- clearTimeout(b);
427
- const $ = k();
428
- $ !== null && !i.aborted && (b = setTimeout(() => void d(), Math.min(Math.max($, p), pt)));
429
+ clearTimeout($);
430
+ const b = E();
431
+ b !== null && !i.aborted && ($ = setTimeout(() => void d(), Math.min(Math.max(b, p), pt)));
429
432
  }
430
433
  async function d() {
431
434
  if (i.aborted || !navigator.onLine) return;
432
- const p = k();
435
+ const p = E();
433
436
  if (p !== null) {
434
437
  if (p <= 0) {
435
438
  if (await x(), i.aborted) return;
436
- l((k() ?? 1) <= 0 ? n : 0);
439
+ l((E() ?? 1) <= 0 ? n : 0);
437
440
  return;
438
441
  }
439
442
  l();
@@ -443,7 +446,7 @@ function Ot(e = {}) {
443
446
  document.visibilityState === "visible" && d();
444
447
  }, u = () => void d();
445
448
  return document.addEventListener("visibilitychange", g), window.addEventListener("online", u), d(), () => {
446
- clearTimeout(b), document.removeEventListener("visibilitychange", g), window.removeEventListener("online", u);
449
+ clearTimeout($), document.removeEventListener("visibilitychange", g), window.removeEventListener("online", u);
447
450
  };
448
451
  }
449
452
  };
@@ -452,7 +455,7 @@ export {
452
455
  ie as ApplicationError,
453
456
  It as ShellOutlet,
454
457
  se as applicationKey,
455
- jt as createApplication,
458
+ Nt as createApplication,
456
459
  Ft as defineFeature,
457
460
  Ot as keepSessionAlive,
458
461
  Wt as provideContext,
@@ -1,2 +1,2 @@
1
1
  export { default as Button } from "./Button.vue";
2
- export { useKeyboardShortcut, matchesShortcut, type KeyboardShortcut } from "./shortcut";
2
+ export { useKeyboardShortcut, matchesShortcut, shortcutKeys, useShortcutRegistry, type KeyboardShortcut, type ShortcutListing } from "./shortcut";
@@ -1,6 +1,8 @@
1
- import { _ as a, m as r, u as s } from "../Button.vue_vue_type_script_setup_true_lang-3f0emVNU.js";
1
+ import { _ as a, m as o, s as r, u, a as e } from "../Button.vue_vue_type_script_setup_true_lang-B1eZgLae.js";
2
2
  export {
3
3
  a as Button,
4
- r as matchesShortcut,
5
- s as useKeyboardShortcut
4
+ o as matchesShortcut,
5
+ r as shortcutKeys,
6
+ u as useKeyboardShortcut,
7
+ e as useShortcutRegistry
6
8
  };
@@ -1,11 +1,18 @@
1
- import { type MaybeRefOrGetter } from "vue";
2
- /** A keyboard shortcut: the key (case-insensitive, as `KeyboardEvent.key`) and exactly the modifiers listed. */
1
+ import { type ComputedRef, type MaybeRefOrGetter } from "vue";
2
+ /**
3
+ * A keyboard shortcut: the key (case-insensitive, as `KeyboardEvent.key`) and exactly the modifiers listed.
4
+ * With a `label` it is listed by `useShortcutRegistry()` (a help dialog) for as long as its owner is mounted.
5
+ */
3
6
  export interface KeyboardShortcut {
4
7
  key: string;
5
8
  ctrlKey?: boolean;
6
9
  shiftKey?: boolean;
7
10
  altKey?: boolean;
8
11
  metaKey?: boolean;
12
+ /** What it does, in the app's language ("Search the list"); a function is read when the list is read, so it follows the locale. An empty text is not listed. */
13
+ label?: string | (() => string);
14
+ /** The heading it is listed under; any name the app has a heading for. The library's own use `"list"` and `"record"`. */
15
+ group?: string;
9
16
  }
10
17
  export declare function matchesShortcut(event: KeyboardEvent, shortcut: KeyboardShortcut): boolean;
11
18
  /**
@@ -15,3 +22,22 @@ export declare function matchesShortcut(event: KeyboardEvent, shortcut: Keyboard
15
22
  * scope. A shortcut without Ctrl, Alt or Meta never fires while the user is typing in a field.
16
23
  */
17
24
  export declare function useKeyboardShortcut(shortcut: MaybeRefOrGetter<KeyboardShortcut | undefined>, run: (event: KeyboardEvent) => void | false): void;
25
+ /** The key and modifiers as keycap texts: `["Ctrl", "S"]`, or `["⌘", "K"]` on Apple platforms; arrows as arrows. */
26
+ export declare function shortcutKeys(shortcut: KeyboardShortcut): string[];
27
+ /** One row of a shortcut help list: what it does and every way of doing it (`/`, or `J` and `→`). */
28
+ export interface ShortcutListing {
29
+ readonly group: string | null;
30
+ readonly label: string;
31
+ /** Each alternative as keycap texts, see `shortcutKeys`. */
32
+ readonly keys: readonly (readonly string[])[];
33
+ }
34
+ /**
35
+ * The shortcuts that exist on the page right now, for a help dialog: every `useKeyboardShortcut`
36
+ * with a `label` whose owner is mounted, the library's own included (list search and filters, the
37
+ * record pager). Rows with the same group and label are one row (two lists on a page share "/");
38
+ * reactive, so the dialog follows pages and locale.
39
+ *
40
+ * const rows = useShortcutRegistry();
41
+ * <dl v-for="row in rows"><dt>{{ row.label }}</dt><dd><kbd v-for="key in row.keys[0]">{{ key }}</kbd></dd></dl>
42
+ */
43
+ export declare function useShortcutRegistry(): ComputedRef<ShortcutListing[]>;
@@ -28,6 +28,7 @@ declare const _default: <Row extends object, Col extends Column<Row>>(__VLS_prop
28
28
  actions?: ((scope: {
29
29
  item: Row;
30
30
  }) => unknown) | undefined;
31
+ } & {
31
32
  toolbar?: () => unknown;
32
33
  empty?: () => unknown;
33
34
  } & {
@@ -0,0 +1,59 @@
1
+ import { type RouteLocationRaw } from "vue-router";
2
+ import { type Column, type RowAction } from "./columns";
3
+ import type { CollectionDisplay } from "./useCollection";
4
+ import type { SortDirection } from "./types";
5
+ declare const _default: <Row extends object, Col extends Column<Row>>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
6
+ props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
7
+ readonly onSort?: ((key: string) => any) | undefined;
8
+ } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onSort"> & {
9
+ columns: readonly Col[];
10
+ rows: readonly Row[];
11
+ rowKey: (row: Row) => string | number;
12
+ display: CollectionDisplay;
13
+ /** Phone rows instead of a table (see `useRowLayout`). */
14
+ phone: boolean;
15
+ /** Where a click on the row goes; null for a row that is not a link. */
16
+ link: (row: Row) => RouteLocationRaw | null;
17
+ /** Text to mark in an identity cell. */
18
+ search?: string;
19
+ /** The sort the header shows; a header sorts (`sort`) only when the column has a `sort` key. */
20
+ sorted?: {
21
+ key: string;
22
+ direction: SortDirection;
23
+ } | null;
24
+ rowActions?: (row: Row) => RowAction[];
25
+ rowLabel?: (row: Row) => string;
26
+ /** Pixels. */
27
+ rowHeight?: number;
28
+ density?: "regular" | "condensed";
29
+ actionsVisible?: boolean;
30
+ skeletonRows: number;
31
+ /** Rows to reserve the height of while loading, so the card does not jump when they land. */
32
+ reserveRows?: number;
33
+ rowClass?: (row: Row) => string | undefined;
34
+ } & Partial<{}>> & import("vue").PublicProps;
35
+ expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
36
+ attrs: any;
37
+ slots: import("./slots").CellSlots<Row, Col> & {
38
+ leading?: ((scope: {
39
+ item: Row;
40
+ compact: boolean;
41
+ }) => unknown) | undefined;
42
+ actions?: ((scope: {
43
+ item: Row;
44
+ }) => unknown) | undefined;
45
+ } & {
46
+ toolbar?: () => unknown;
47
+ empty?: () => unknown;
48
+ } & {
49
+ /** What a failed load shows. */
50
+ failed?: () => unknown;
51
+ };
52
+ emit: (evt: "sort", key: string) => void;
53
+ }>) => import("vue").VNode & {
54
+ __ctx?: Awaited<typeof __VLS_setup>;
55
+ };
56
+ export default _default;
57
+ type __VLS_PrettifyLocal<T> = {
58
+ [K in keyof T]: T[K];
59
+ } & {};
@@ -1,4 +1,4 @@
1
- import { type Column, type RowAction } from "./columns";
1
+ import type { Column, RowAction } from "./columns";
2
2
  import type { CollectionSlots } from "./slots";
3
3
  import type { Collection } from "./useCollection";
4
4
  declare const _default: <Row extends object, Col extends Column<Row>>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
@@ -0,0 +1,47 @@
1
+ import type { RouteLocationRaw } from "vue-router";
2
+ import type { Column, RowAction } from "./columns";
3
+ declare const _default: <Row extends object, const Col extends Column<Row, never>>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
4
+ props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, never> & {
5
+ rows: readonly Row[];
6
+ columns: readonly Col[];
7
+ rowKey: (row: Row) => string | number;
8
+ /** Skeleton rows instead of the rows (and instead of the empty state). */
9
+ loading?: boolean;
10
+ /** How many skeleton rows `loading` shows. */
11
+ skeletonRows?: number;
12
+ /** Where a row's record lives: the row opens it on click, and an identity column links to it. */
13
+ recordRoute?: (row: Row) => RouteLocationRaw;
14
+ /** Quick actions per row: swiped in on phones (links), and the row's context menu (long press, right click). */
15
+ rowActions?: (row: Row) => RowAction[];
16
+ /** The accessible name of a row's menu and More button, e.g. the record's name. */
17
+ rowLabel?: (row: Row) => string;
18
+ /** Pixels. */
19
+ rowHeight?: number;
20
+ density?: "regular" | "condensed";
21
+ /** The row's actions are the only way to perform them, so the More button shows in the row. */
22
+ actionsVisible?: boolean;
23
+ /** Extra classes for a row, e.g. to set apart a total or the newest row. */
24
+ rowClass?: (row: Row) => string | undefined;
25
+ } & Partial<{}>> & import("vue").PublicProps;
26
+ expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
27
+ attrs: any;
28
+ slots: import("./slots").CellSlots<Row, Col> & {
29
+ leading?: ((scope: {
30
+ item: Row;
31
+ compact: boolean;
32
+ }) => unknown) | undefined;
33
+ actions?: ((scope: {
34
+ item: Row;
35
+ }) => unknown) | undefined;
36
+ } & {
37
+ /** What shows when there are no rows; "No data" by default. */
38
+ empty?: () => unknown;
39
+ };
40
+ emit: {};
41
+ }>) => import("vue").VNode & {
42
+ __ctx?: Awaited<typeof __VLS_setup>;
43
+ };
44
+ export default _default;
45
+ type __VLS_PrettifyLocal<T> = {
46
+ [K in keyof T]: T[K];
47
+ } & {};
@@ -0,0 +1,19 @@
1
+ import type { RowAction } from "./columns";
2
+ /**
3
+ * The actions of a row as icon buttons in its actions cell: view, edit, delete, download. The same
4
+ * `RowAction[]` a table gives its swipe and context menu, so a row's actions are written once; the
5
+ * page builds the array from what the user may do (`access.can(...)`), so there is nothing to hide
6
+ * here. A link (`href`) is an anchor, a command (`onSelect`) a button; `critical` is red.
7
+ *
8
+ * <template #actions="{ item }"><RowActions :actions="rowActions(item)" :disabled="item.locked" /></template>
9
+ *
10
+ * `disabled` greys out every button (a locked row); it does not hide them.
11
+ */
12
+ type __VLS_Props = {
13
+ actions: readonly RowAction[];
14
+ disabled?: boolean;
15
+ };
16
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
17
+ disabled: boolean;
18
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
19
+ export default _default;
@@ -84,6 +84,8 @@ export type Column<Row, Sort extends string = string> = ColumnCommon<Row, Sort>
84
84
  * const columns = [{ key: "title", label: t("title"), kind: "identity", mobile: "primary" }] satisfies CollectionColumns<Ticket>;
85
85
  */
86
86
  export type CollectionColumns<Row, Sort extends string = string> = readonly Column<Row, Sort>[];
87
+ /** The columns of a `DataTable`: the collection's, without a `sort` key (a table over an array keeps its order). */
88
+ export type TableColumns<Row> = readonly Column<Row, never>[];
87
89
  /** A quick action of a row: swiped in on phones (links only) and listed in the row's context menu. */
88
90
  export interface RowAction {
89
91
  key: string;
@@ -5,7 +5,7 @@ export type { Collection, CollectionDisplay, LinkedQuery, SavedViewsHandle, UseC
5
5
  export type { CollectionLoader, ListPage, CollectionQuery, CollectionStateSource, LoadContext, SortDirection } from "./types";
6
6
  export { httpList, listParams, readListPage } from "./http";
7
7
  export { LIST_CONTEXT_PARAM } from "./location";
8
- export type { CollectionColumns, Column, ColumnKey, ColumnKind, ColumnValue, MobileRole, RowAction, SlotKey } from "./columns";
8
+ export type { CollectionColumns, Column, ColumnKey, ColumnKind, ColumnValue, MobileRole, RowAction, SlotKey, TableColumns } from "./columns";
9
9
  export type { FilterDescriptor, FilterOption, ViewDescriptor } from "./filters";
10
10
  export { useCollectionNeighbors } from "./neighbors";
11
11
  export type { CollectionNeighbors, Neighbor, NeighborOptions } from "./neighbors";
@@ -14,6 +14,8 @@ export type { SavedView, SavedViews, SavedViewState } from "./savedViews";
14
14
  export { default as CollectionPage } from "./CollectionPage.vue";
15
15
  export { default as CollectionTable } from "./CollectionTable.vue";
16
16
  export { default as CollectionCell } from "./CollectionCell.vue";
17
+ export { default as DataTable } from "./DataTable.vue";
18
+ export { default as RowActions } from "./RowActions.vue";
17
19
  export { default as RecordIdentity } from "./RecordIdentity.vue";
18
20
  export { DATE_PRESETS, useDatePresetFilter } from "./datePresets";
19
- export type { CellSlots, CollectionSlots } from "./slots";
21
+ export type { CellSlots, CollectionSlots, RowsSlots } from "./slots";