@wssto2/vue-core 0.4.4 → 0.4.6

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 (73) hide show
  1. package/dist/{Activity-BH0jQxZs.js → Activity-BVk8iG3X.js} +2 -2
  2. package/dist/{AdaptivePageShell.vue_vue_type_script_setup_true_lang-DxD6JvyK.js → AdaptivePageShell.vue_vue_type_script_setup_true_lang-B7qSUiee.js} +1 -1
  3. package/dist/{Changes-DS81sZj9.js → Changes-CaiZpcyW.js} +2 -2
  4. package/dist/CollectionPage.vue_vue_type_script_setup_true_lang-kBBHIJTB.js +1520 -0
  5. package/dist/{DataTable.vue_vue_type_script_setup_true_lang-DBtMgcW6.js → DataTable.vue_vue_type_script_setup_true_lang-KPm5NrDE.js} +1 -1
  6. package/dist/{DeadLetters-BqKtaowL.js → DeadLetters-BOMgmmOg.js} +3 -3
  7. package/dist/{General-CK-9LrQ2.js → General-BaW63VQg.js} +2 -2
  8. package/dist/IconTile.vue_vue_type_script_setup_true_lang-_FXvaj93.js +50 -0
  9. package/dist/{Menu.vue_vue_type_script_setup_true_lang-ClsOlOSr.js → Menu.vue_vue_type_script_setup_true_lang-uPmxWvds.js} +56 -50
  10. package/dist/{NewRolePage-CziDdoeG.js → NewRolePage-B8OGQE-A.js} +3 -3
  11. package/dist/{ProfilePage-x063Zij2.js → ProfilePage-Bbv5KH3L.js} +4 -4
  12. package/dist/{RecordHeader.vue_vue_type_script_setup_true_lang-Bua3wbN6.js → RecordHeader.vue_vue_type_script_setup_true_lang-D87Hs75d.js} +1 -1
  13. package/dist/{ResourcePage.vue_vue_type_script_setup_true_lang-CzP4BNh7.js → ResourcePage.vue_vue_type_script_setup_true_lang-gJGEfLzX.js} +1 -1
  14. package/dist/{RoleEditor.vue_vue_type_script_setup_true_lang-BjhaIqqG.js → RoleEditor.vue_vue_type_script_setup_true_lang-4YJhNgbn.js} +1 -1
  15. package/dist/{RolePage-Cecu3BKn.js → RolePage-Bn0re7VE.js} +6 -6
  16. package/dist/{RolesPage-DIL35QcF.js → RolesPage-CjEAQvTq.js} +3 -3
  17. package/dist/{SectionList.vue_vue_type_script_setup_true_lang-CaF3LPbQ.js → SectionList.vue_vue_type_script_setup_true_lang-B0p_8xQG.js} +2 -2
  18. package/dist/{SectionNavigator.vue_vue_type_script_setup_true_lang-BJfEOvEf.js → SectionNavigator.vue_vue_type_script_setup_true_lang-ROl9_pdO.js} +3 -3
  19. package/dist/SelectField.vue_vue_type_script_setup_true_lang-BJoAkBo2.js +437 -0
  20. package/dist/{SessionList.vue_vue_type_script_setup_true_lang-D5KRitar.js → SessionList.vue_vue_type_script_setup_true_lang-D4k5QeWS.js} +1 -1
  21. package/dist/{Sessions-DhHIVk7e.js → Sessions-r9WHf0nU.js} +2 -2
  22. package/dist/{SettingsPage-BuGtZcae.js → SettingsPage-Dcib_TK0.js} +2 -2
  23. package/dist/{SignIn-DRls5eYK.js → SignIn-DJ-ai_ap.js} +2 -2
  24. package/dist/{SignInPage-D9wR46KD.js → SignInPage-CJAsxvc6.js} +1 -1
  25. package/dist/{SignInTable.vue_vue_type_script_setup_true_lang-CifEaH7c.js → SignInTable.vue_vue_type_script_setup_true_lang-ALAuc0sI.js} +1 -1
  26. package/dist/{SignIns-BMBFeBrK.js → SignIns-NnIqezxn.js} +2 -2
  27. package/dist/ToneDot.vue_vue_type_script_setup_true_lang-99rNn-L5.js +24 -0
  28. package/dist/{UserRecord-BOCP5XC6.js → UserRecord-JZFQ40hK.js} +6 -6
  29. package/dist/{UsersList-Df6HeAAO.js → UsersList-cfhb1GE7.js} +4 -4
  30. package/dist/access/index.js +1 -1
  31. package/dist/collection/CollectionCell.vue.d.ts +2 -0
  32. package/dist/collection/RecordIdentity.vue.d.ts +6 -0
  33. package/dist/collection/datePresets.d.ts +8 -4
  34. package/dist/collection/filters.d.ts +4 -0
  35. package/dist/collection/index.js +49 -49
  36. package/dist/collection/rowInteractions.d.ts +2 -0
  37. package/dist/collection/state.d.ts +10 -5
  38. package/dist/collection/useCollection.d.ts +20 -5
  39. package/dist/controls/IconTile.vue.d.ts +10 -3
  40. package/dist/controls/index.js +1 -1
  41. package/dist/form/I18nField.vue.d.ts +1 -1
  42. package/dist/form/TextareaField.vue.d.ts +1 -1
  43. package/dist/form/index.js +4 -4
  44. package/dist/form/options.d.ts +3 -0
  45. package/dist/http-D_D9YbLH.js +194 -0
  46. package/dist/identity/index.js +1 -1
  47. package/dist/{index-EkQmsbBQ.js → index-7QcMXQZq.js} +2 -2
  48. package/dist/{index-BykMr7eH.js → index-By5B18A3.js} +10 -10
  49. package/dist/{index-BwMaMqSc.js → index-CixCeO47.js} +5 -5
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.js +1 -1
  52. package/dist/{neighbors-DpaIMQAL.js → neighbors-BRf4Eh2R.js} +1 -1
  53. package/dist/notifications/index.js +1 -1
  54. package/dist/overlay/AlertDialog.vue.d.ts +2 -2
  55. package/dist/overlay/Menu.vue.d.ts +3 -0
  56. package/dist/overlay/index.js +1 -1
  57. package/dist/page/AdaptivePageShell.vue.d.ts +2 -2
  58. package/dist/page/ResourceHeader.vue.d.ts +2 -2
  59. package/dist/page/index.js +5 -5
  60. package/dist/resource/index.js +1 -1
  61. package/dist/{rowLayout-CZ7uZFnE.js → rowLayout-BkQWulan.js} +239 -221
  62. package/dist/shell/NavigationList.vue.d.ts +1 -1
  63. package/dist/shell/index.js +1 -1
  64. package/dist/state/ToneDot.vue.d.ts +12 -0
  65. package/dist/{status-DyvlO552.js → status-Ct8ixCoS.js} +2 -2
  66. package/dist/styles.css +1 -1
  67. package/package.json +1 -1
  68. package/src/styles/collection.css +1 -1
  69. package/src/styles/theme.css +7 -0
  70. package/dist/CollectionPage.vue_vue_type_script_setup_true_lang-BZRdVhZo.js +0 -1485
  71. package/dist/IconTile.vue_vue_type_script_setup_true_lang-BpIjgu5E.js +0 -40
  72. package/dist/SelectField.vue_vue_type_script_setup_true_lang-7O1BAx04.js +0 -423
  73. package/dist/http-CNcDHSOj.js +0 -194
@@ -6,6 +6,9 @@ import type { RouteLocationRaw } from "vue-router";
6
6
  *
7
7
  * <RecordIdentity :to="recordRoute" :title="name" :subtitle="email" subtitle-selectable />
8
8
  *
9
+ * `spread` (the phone row) lets the two lines be cells of the grid they sit in: the title in the first column of the first
10
+ * row, the subtitle across the full width of the second, so something beside the title (a status) never narrows the subtitle.
11
+ *
9
12
  * `highlight` (the list's search text) marks where it matches the title, in `<mark>`: what found the row is visible.
10
13
  */
11
14
  type __VLS_Props = {
@@ -17,11 +20,14 @@ type __VLS_Props = {
17
20
  subtitleSelectable?: boolean;
18
21
  /** The search text to mark in the title (its words, any case). */
19
22
  highlight?: string | null;
23
+ /** Lays the lines out as cells of the parent grid (see above) instead of a column of its own. */
24
+ spread?: boolean;
20
25
  };
21
26
  declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
22
27
  to: RouteLocationRaw | null;
23
28
  subtitle: string | null;
24
29
  subtitleSelectable: boolean;
25
30
  highlight: string | null;
31
+ spread: boolean;
26
32
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
27
33
  export default _default;
@@ -1,11 +1,15 @@
1
+ import { type ComputedRef, type MaybeRefOrGetter } from "vue";
1
2
  import type { FilterDescriptor } from "./filters";
2
3
  /** The presets go-core's date helper understands (`utils.DateRange`). */
3
4
  export declare const DATE_PRESETS: readonly ["today", "yesterday", "this_week", "last_week", "this_month", "last_month", "this_year", "last_year"];
4
5
  /**
5
6
  * A filter over a date column with go-core's presets (today, this week, last month...), its labels
6
- * translated. Call it while a component is set up, inside the `filters` computed so a locale change
7
- * re-renders the labels:
7
+ * translated. Call it once while a component is set up (it takes `t` from `useI18n`, which exists
8
+ * only then) and use the result in the `filters` computed: the descriptor's labels follow the locale,
9
+ * so changing the language while the list is open re-labels it. `label` may be a getter, which
10
+ * follows the locale too.
8
11
  *
9
- * const filters = computed(() => [useDatePresetFilter("created_at"), …]);
12
+ * const created = useDatePresetFilter("created_at");
13
+ * const filters = computed(() => [created.value, …]);
10
14
  */
11
- export declare function useDatePresetFilter<Filter extends string>(key: Filter, label?: string): FilterDescriptor<Filter>;
15
+ export declare function useDatePresetFilter<Filter extends string>(key: Filter, label?: MaybeRefOrGetter<string>): ComputedRef<FilterDescriptor<Filter>>;
@@ -1,8 +1,11 @@
1
1
  import type { IconName } from "../icon";
2
+ import type { Tone } from "../state";
2
3
  export interface FilterOption {
3
4
  value: string | number;
4
5
  label: string;
5
6
  icon?: IconName;
7
+ /** A status dot before the label, in the tone's colour, wherever the option is listed or shown as the chosen one. */
8
+ dot?: Tone;
6
9
  /** For a filter with `dependsOn`: the parent value this option belongs to; offered only while the parent is empty or includes it. */
7
10
  parentValue?: string | number;
8
11
  }
@@ -58,6 +61,7 @@ export declare function joinRange(from: string | number | null | undefined, unti
58
61
  export declare function narrowedOptions(filter: FilterDescriptor, parentValue: string | number | null | undefined): {
59
62
  value: string;
60
63
  label: string;
64
+ dot?: Tone;
61
65
  }[];
62
66
  /** An applied filter as a removable token. */
63
67
  export interface FilterChip {
@@ -1,15 +1,15 @@
1
- import { D as M, L as O, a as V, h as j, l as U, r as G } from "../http-CNcDHSOj.js";
2
- import { _ as Z, a as q, u as H } from "../CollectionPage.vue_vue_type_script_setup_true_lang-BZRdVhZo.js";
3
- import { u as K } from "../neighbors-DpaIMQAL.js";
4
- import { a as W, b as Y } from "../rowLayout-CZ7uZFnE.js";
5
- import { _ as te } from "../DataTable.vue_vue_type_script_setup_true_lang-DBtMgcW6.js";
6
- import { defineComponent as y, openBlock as c, createElementBlock as d, Fragment as h, renderList as v, createBlock as k, unref as u, withCtx as C, normalizeClass as m, createVNode as p, createCommentVNode as g } from "vue";
1
+ import { D as O, L as j, a as U, h as G, l as X, r as Z } from "../http-D_D9YbLH.js";
2
+ import { _ as H, a as J, u as K } from "../CollectionPage.vue_vue_type_script_setup_true_lang-kBBHIJTB.js";
3
+ import { u as W } from "../neighbors-BRf4Eh2R.js";
4
+ import { a as ee, b as te } from "../rowLayout-BkQWulan.js";
5
+ import { _ as oe } from "../DataTable.vue_vue_type_script_setup_true_lang-KPm5NrDE.js";
6
+ import { defineComponent as y, openBlock as c, createElementBlock as d, Fragment as h, renderList as v, createBlock as k, unref as f, withCtx as C, normalizeClass as m, createVNode as p, createCommentVNode as g, computed as w, toValue as E } from "vue";
7
7
  import { _ } from "../Icon.vue_vue_type_script_lang-D7oC-d-S.js";
8
- import { _ as w } from "../Tooltip.vue_vue_type_script_setup_true_lang-OOD_XNWx.js";
9
- import { useI18n as E } from "vue-i18n";
10
- function R(r = {}) {
8
+ import { _ as S } from "../Tooltip.vue_vue_type_script_setup_true_lang-OOD_XNWx.js";
9
+ import { useI18n as T } from "vue-i18n";
10
+ function B(r = {}) {
11
11
  const s = new Map(Object.entries(r).map(([t, e]) => [t, [...e]]));
12
- let n = 1;
12
+ let a = 1;
13
13
  const o = (t) => {
14
14
  let e = s.get(t);
15
15
  return e || s.set(t, e = []), e;
@@ -19,29 +19,29 @@ function R(r = {}) {
19
19
  return [...o(t)];
20
20
  },
21
21
  async save(t, e, i) {
22
- const a = o(t), l = a.findIndex((x) => x.name === e), f = { id: l === -1 ? `view-${n++}` : a[l].id, name: e, state: i };
23
- return l === -1 ? a.push(f) : a[l] = f, f;
22
+ const n = o(t), l = n.findIndex((x) => x.name === e), u = { id: l === -1 ? `view-${a++}` : n[l].id, name: e, state: i };
23
+ return l === -1 ? n.push(u) : n[l] = u, u;
24
24
  },
25
25
  async remove(t, e) {
26
- const i = o(t), a = i.findIndex((l) => l.id === e);
27
- a !== -1 && i.splice(a, 1);
26
+ const i = o(t), n = i.findIndex((l) => l.id === e);
27
+ n !== -1 && i.splice(n, 1);
28
28
  }
29
29
  };
30
30
  }
31
- const S = {
31
+ const A = {
32
32
  key: 0,
33
33
  class: "flex items-center justify-center gap-1",
34
34
  "data-test": "row-actions"
35
- }, T = ["href", "target", "rel", "aria-label", "data-action"], A = ["aria-label", "data-action", "disabled", "onClick"], b = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus", $ = /* @__PURE__ */ y({
35
+ }, P = ["href", "target", "rel", "aria-label", "data-action"], L = ["aria-label", "data-action", "disabled", "onClick"], b = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus", N = /* @__PURE__ */ y({
36
36
  __name: "RowActions",
37
37
  props: {
38
38
  actions: {},
39
39
  disabled: { type: Boolean, default: !1 }
40
40
  },
41
41
  setup(r) {
42
- const s = r, n = (o) => o.tone === "critical" ? "text-status-danger-content hover:bg-status-danger-surface" : "text-content-link hover:bg-tint-soft";
43
- return (o, t) => s.actions.length > 0 ? (c(), d("div", S, [
44
- (c(!0), d(h, null, v(s.actions, (e) => (c(), k(u(w), {
42
+ const s = r, a = (o) => o.tone === "critical" ? "text-status-danger-content hover:bg-status-danger-surface" : "text-content-link hover:bg-tint-soft";
43
+ return (o, t) => s.actions.length > 0 ? (c(), d("div", A, [
44
+ (c(!0), d(h, null, v(s.actions, (e) => (c(), k(f(S), {
45
45
  key: e.key,
46
46
  text: e.label,
47
47
  side: "left"
@@ -54,58 +54,58 @@ const S = {
54
54
  rel: e.external ? "noopener" : void 0,
55
55
  "aria-label": e.label,
56
56
  "data-action": e.key,
57
- class: m(["inline-flex rounded-md p-1.5 transition-colors", [n(e), b]])
57
+ class: m(["inline-flex rounded-md p-1.5 transition-colors", [a(e), b]])
58
58
  }, [
59
- p(u(_), {
59
+ p(f(_), {
60
60
  name: e.icon,
61
61
  size: 18
62
62
  }, null, 8, ["name"])
63
- ], 10, T)) : (c(), d("button", {
63
+ ], 10, P)) : (c(), d("button", {
64
64
  key: 1,
65
65
  type: "button",
66
66
  "aria-label": e.label,
67
67
  "data-action": e.key,
68
68
  disabled: s.disabled,
69
- class: m(["inline-flex cursor-pointer rounded-md p-1.5 transition-colors disabled:pointer-events-none disabled:opacity-40", [n(e), b]]),
69
+ class: m(["inline-flex cursor-pointer rounded-md p-1.5 transition-colors disabled:pointer-events-none disabled:opacity-40", [a(e), b]]),
70
70
  onClick: (i) => e.onSelect?.()
71
71
  }, [
72
- p(u(_), {
72
+ p(f(_), {
73
73
  name: e.icon,
74
74
  size: 18
75
75
  }, null, 8, ["name"])
76
- ], 10, A))
76
+ ], 10, L))
77
77
  ]),
78
78
  _: 2
79
79
  }, 1032, ["text"]))), 128))
80
80
  ])) : g("", !0);
81
81
  }
82
- }), P = ["today", "yesterday", "this_week", "last_week", "this_month", "last_month", "this_year", "last_year"];
83
- function B(r, s) {
84
- const { t: n } = E();
85
- return {
82
+ }), D = ["today", "yesterday", "this_week", "last_week", "this_month", "last_month", "this_year", "last_year"];
83
+ function V(r, s) {
84
+ const { t: a } = T();
85
+ return w(() => ({
86
86
  key: r,
87
87
  icon: "calendarEventFill",
88
- label: s ?? n("core.collection.date_presets.label"),
88
+ label: E(s) ?? a("core.collection.date_presets.label"),
89
89
  type: "select",
90
- options: P.map((o) => ({ value: o, label: n(`core.collection.date_presets.options.${o}`) }))
91
- };
90
+ options: D.map((o) => ({ value: o, label: a(`core.collection.date_presets.options.${o}`) }))
91
+ }));
92
92
  }
93
93
  export {
94
- W as CollectionCell,
95
- Z as CollectionPage,
96
- q as CollectionTable,
97
- P as DATE_PRESETS,
98
- M as DEFAULT_PAGE_SIZES,
99
- te as DataTable,
100
- O as LIST_CONTEXT_PARAM,
101
- Y as RecordIdentity,
102
- $ as RowActions,
103
- R as createMemorySavedViews,
104
- V as defineCollection,
105
- j as httpList,
106
- U as listParams,
107
- G as readListPage,
108
- H as useCollection,
109
- K as useCollectionNeighbors,
110
- B as useDatePresetFilter
94
+ ee as CollectionCell,
95
+ H as CollectionPage,
96
+ J as CollectionTable,
97
+ D as DATE_PRESETS,
98
+ O as DEFAULT_PAGE_SIZES,
99
+ oe as DataTable,
100
+ j as LIST_CONTEXT_PARAM,
101
+ te as RecordIdentity,
102
+ N as RowActions,
103
+ B as createMemorySavedViews,
104
+ U as defineCollection,
105
+ G as httpList,
106
+ X as listParams,
107
+ Z as readListPage,
108
+ K as useCollection,
109
+ W as useCollectionNeighbors,
110
+ V as useDatePresetFilter
111
111
  };
@@ -22,6 +22,7 @@ export declare function useRowInteractions<Row>(options: RowInteractionOptions<R
22
22
  id: string;
23
23
  label: string;
24
24
  icon?: import("../icon").IconName | undefined;
25
+ dot?: import("../state").Tone | undefined;
25
26
  section?: string | undefined;
26
27
  tone?: "critical" | undefined;
27
28
  disabled?: boolean | undefined;
@@ -33,6 +34,7 @@ export declare function useRowInteractions<Row>(options: RowInteractionOptions<R
33
34
  id: string;
34
35
  label: string;
35
36
  icon?: import("../icon").IconName | undefined;
37
+ dot?: import("../state").Tone | undefined;
36
38
  section?: string | undefined;
37
39
  tone?: "critical" | undefined;
38
40
  disabled?: boolean | undefined;
@@ -2,18 +2,23 @@ import type { CollectionDefinition } from "./definition";
2
2
  import type { CollectionQuery } from "./types";
3
3
  export type Json = Readonly<Record<string, unknown>>;
4
4
  /** The query of `candidate` (untrusted, compact keys) made valid for `definition`: every bad field is its default. */
5
- export declare function sanitizeState<Row, Sort extends string, Filter extends string, View extends string>(definition: CollectionDefinition<Row, Sort, Filter, View>, candidate: Json): CollectionQuery<Sort, Filter, View>;
6
- /** The compact text of a query. Sensitive filters are left out. */
7
- export declare function encodeState<Row, Sort extends string, Filter extends string, View extends string>(definition: CollectionDefinition<Row, Sort, Filter, View>, query: CollectionQuery<Sort, Filter, View>): string;
5
+ export declare function sanitizeState<Row, Sort extends string, Filter extends string, View extends string>(definition: CollectionDefinition<Row, Sort, Filter, View>, candidate: Json, start?: CollectionQuery<Sort, Filter, View>): CollectionQuery<Sort, Filter, View>;
6
+ /**
7
+ * The compact text of a query. Sensitive filters are left out. `start` is a list's own starting
8
+ * state (see `UseCollectionOptions.defaults`): the text stays readable without it (a record page's
9
+ * `from` is decoded against the bare definition), so whatever either side defaults is written out,
10
+ * even when empty: `f` as `{}`, `s` as `""`, `w` as `""`.
11
+ */
12
+ export declare function encodeState<Row, Sort extends string, Filter extends string, View extends string>(definition: CollectionDefinition<Row, Sort, Filter, View>, query: CollectionQuery<Sort, Filter, View>, start?: CollectionQuery<Sort, Filter, View>): string;
8
13
  /**
9
14
  * The query stored (compact keys, as a link or a saved view holds them) under `stored.v`, migrated if
10
15
  * it is of another version: null when the definition cannot read it (the caller then keeps what it has).
11
16
  */
12
- export declare function restoreState<Row, Sort extends string, Filter extends string, View extends string>(definition: CollectionDefinition<Row, Sort, Filter, View>, stored: Json): CollectionQuery<Sort, Filter, View> | null;
17
+ export declare function restoreState<Row, Sort extends string, Filter extends string, View extends string>(definition: CollectionDefinition<Row, Sort, Filter, View>, stored: Json, start?: CollectionQuery<Sort, Filter, View>): CollectionQuery<Sort, Filter, View> | null;
13
18
  /**
14
19
  * The query a stored text stands for: null when it is missing, corrupt or of a version the
15
20
  * definition cannot migrate (the caller then uses the defaults), otherwise the validated query.
16
21
  */
17
- export declare function decodeState<Row, Sort extends string, Filter extends string, View extends string>(definition: CollectionDefinition<Row, Sort, Filter, View>, raw: unknown): CollectionQuery<Sort, Filter, View> | null;
22
+ export declare function decodeState<Row, Sort extends string, Filter extends string, View extends string>(definition: CollectionDefinition<Row, Sort, Filter, View>, raw: unknown, start?: CollectionQuery<Sort, Filter, View>): CollectionQuery<Sort, Filter, View> | null;
18
23
  /** A stable text of a query: the cache key of a page, and a cheap equality. */
19
24
  export declare function queryKey(query: CollectionQuery): string;
@@ -2,7 +2,7 @@ import { type ComputedRef, type MaybeRefOrGetter, type Ref } from "vue";
2
2
  import { type RouteLocationRaw } from "vue-router";
3
3
  import type { AsyncState } from "../state";
4
4
  import type { Column } from "./columns";
5
- import type { CollectionDefinition } from "./definition";
5
+ import { type CollectionDefinition } from "./definition";
6
6
  import { type FilterDescriptor, type ViewDescriptor } from "./filters";
7
7
  import type { SavedView, SavedViewState, SavedViews } from "./savedViews";
8
8
  import type { ListPage, CollectionQuery, CollectionStateSource, SortDirection } from "./types";
@@ -22,7 +22,7 @@ export interface LinkedQuery<Filter extends string> {
22
22
  /** Parameters that only label a filter (`line_name` for `line`): dropped along with it. */
23
23
  consume?: readonly string[];
24
24
  }
25
- export interface UseCollectionOptions<Row, Filter extends string, View extends string, Col extends Column<Row>> {
25
+ export interface UseCollectionOptions<Row, Filter extends string, View extends string, Col extends Column<Row>, Sort extends string = string> {
26
26
  /** Where the list keeps its state; two lists on one page need two URL keys. */
27
27
  state: CollectionStateSource;
28
28
  columns?: MaybeRefOrGetter<readonly Col[]>;
@@ -33,6 +33,21 @@ export interface UseCollectionOptions<Row, Filter extends string, View extends s
33
33
  /** Offers "Saved views" on the list. */
34
34
  savedViews?: SavedViews;
35
35
  linked?: LinkedQuery<Filter>;
36
+ /**
37
+ * This use's starting state, over the definition's `defaults` (each field given replaces the
38
+ * definition's): where the list opens when the URL holds none, and what `reset()` returns to. A list
39
+ * that opens on the user's own location starts here. It is where the list starts, not a search the
40
+ * user ran: `isFiltered` (so `display`) counts a filter or the search only when it differs from it,
41
+ * so an empty result under the start is `"empty"`, not `"no-matches"`. Clearing the filter shows
42
+ * everything, and the start is still sent to the backend like any filter.
43
+ */
44
+ defaults?: Readonly<{
45
+ filters?: Readonly<Partial<Record<NoInfer<Filter>, string>>>;
46
+ search?: string;
47
+ view?: NoInfer<View> | null;
48
+ sort?: NoInfer<Sort> | null;
49
+ direction?: SortDirection;
50
+ }>;
36
51
  }
37
52
  /** What the list shows, derived from its state: one branch to render per value. */
38
53
  export type CollectionDisplay =
@@ -85,7 +100,7 @@ export interface Collection<Row, Sort extends string = string, Filter extends st
85
100
  readonly rows: ComputedRef<readonly Row[]>;
86
101
  readonly total: ComputedRef<number>;
87
102
  readonly display: ComputedRef<CollectionDisplay>;
88
- /** A search or a filter applies. */
103
+ /** A search or a filter applies; one that is the use's starting state (`defaults`) does not count. */
89
104
  readonly isFiltered: ComputedRef<boolean>;
90
105
  /** The failure of the last request (an `ApiError` for requests made through the client); null when it did not fail. */
91
106
  readonly error: Readonly<Ref<unknown>>;
@@ -112,7 +127,7 @@ export interface Collection<Row, Sort extends string = string, Filter extends st
112
127
  /** Clears every filter and the search. */
113
128
  clearFilters(): void;
114
129
  setView(view: View | null): void;
115
- /** Back to the definition's defaults. */
130
+ /** Back to the starting state: the use's `defaults` over the definition's. */
116
131
  reset(): void;
117
132
  /** The link of a row's record, carrying the list's state; null without `recordRoute`. */
118
133
  recordLocation(row: Row): RouteLocationRaw | null;
@@ -132,4 +147,4 @@ export interface Collection<Row, Sort extends string = string, Filter extends st
132
147
  * request only, treats a cancelled request as nothing happened, and follows the URL when the
133
148
  * user goes back or forward. It stops with the scope it was created in.
134
149
  */
135
- export declare function useCollection<Row, Sort extends string, Filter extends string, View extends string, const Col extends Column<Row> = Column<Row>>(definition: CollectionDefinition<Row, Sort, Filter, View>, options: UseCollectionOptions<Row, Filter, View, Col>): Collection<Row, Sort, Filter, View, Col>;
150
+ export declare function useCollection<Row, Sort extends string, Filter extends string, View extends string, const Col extends Column<Row> = Column<Row>>(definition: CollectionDefinition<Row, Sort, Filter, View>, options: UseCollectionOptions<Row, Filter, View, Col, Sort>): Collection<Row, Sort, Filter, View, Col>;
@@ -7,18 +7,25 @@ import { type IconName } from "../icon";
7
7
  * <IconTile tone="brand" icon="carLine" /> the app's own programmes
8
8
  * <IconTile tone="anchor" text="N" /> integrations, navigation
9
9
  * <IconTile tone="neutral" icon="serverLine" size="lg" /> system and export
10
+ * <IconTile weight="soft" size="sm" icon="user" /> a list row's leading mark: quiet, not a block
11
+ *
12
+ * `weight="soft"` is a light tint of the tone with its glyph (and a hairline ring) instead of the solid fill:
13
+ * for tiles on white surfaces, where a solid block reads as a missing photo.
10
14
  */
11
15
  type __VLS_Props = {
12
16
  tone?: "brand" | "anchor" | "neutral";
13
17
  icon?: IconName;
14
18
  text?: string;
15
- /** `row` follows the theme's row metrics (22 px desktop, 29 px compact). */
16
- size?: "row" | "md" | "lg";
19
+ /** `solid` (default) fills the tile; `soft` is a light tint with the tone's glyph. */
20
+ weight?: "solid" | "soft";
21
+ /** `row` follows the theme's row metrics (22 px desktop, 29 px compact); `sm` is 32 px, a list row's leading tile. */
22
+ size?: "row" | "sm" | "md" | "lg";
17
23
  };
18
24
  declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
19
25
  text: string;
20
- size: "row" | "md" | "lg";
26
+ size: "row" | "sm" | "md" | "lg";
21
27
  tone: "brand" | "anchor" | "neutral";
22
28
  icon: IconName;
29
+ weight: "solid" | "soft";
23
30
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
31
  export default _default;
@@ -1,4 +1,4 @@
1
- import { _ as A } from "../IconTile.vue_vue_type_script_setup_true_lang-BpIjgu5E.js";
1
+ import { _ as A } from "../IconTile.vue_vue_type_script_setup_true_lang-_FXvaj93.js";
2
2
  import { defineComponent as p, useSlots as c, openBlock as r, createElementBlock as d, normalizeClass as u, createElementVNode as f, renderSlot as m, toDisplayString as b, createVNode as x, unref as h, useModel as v, useTemplateRef as _, withDirectives as y, mergeProps as g, vModelText as k, mergeModels as w } from "vue";
3
3
  import { _ as B } from "../Icon.vue_vue_type_script_lang-D7oC-d-S.js";
4
4
  import { _ as N } from "../DateButton.vue_vue_type_script_setup_true_lang-EcqrfWKz.js";
@@ -37,8 +37,8 @@ declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {
37
37
  label: string;
38
38
  error: string;
39
39
  required: boolean;
40
- rows: number;
41
40
  presentation: "control" | "value";
41
+ rows: number;
42
42
  hint: string;
43
43
  editable: boolean;
44
44
  lockedReason: string;
@@ -30,8 +30,8 @@ declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {
30
30
  label: string;
31
31
  error: string;
32
32
  required: boolean;
33
- rows: number;
34
33
  presentation: "control" | "value";
34
+ rows: number;
35
35
  stacked: boolean;
36
36
  hint: string;
37
37
  editable: boolean;
@@ -31,8 +31,8 @@ import { _ as us } from "../FormView.vue_vue_type_script_setup_true_lang-cr0xNDX
31
31
  import { a as qt } from "../environment-Dva-SG8D.js";
32
32
  import { _ as Mt } from "../NumberField.vue_vue_type_script_setup_true_lang-C7N5nq0P.js";
33
33
  import { _ as Ot } from "../Sheet.vue_vue_type_script_setup_true_lang-DgOFV4fa.js";
34
- import { u as jt, a as Ue } from "../SelectField.vue_vue_type_script_setup_true_lang-7O1BAx04.js";
35
- import { _ as cs, b as fs } from "../SelectField.vue_vue_type_script_setup_true_lang-7O1BAx04.js";
34
+ import { u as jt, a as Ue } from "../SelectField.vue_vue_type_script_setup_true_lang-BJoAkBo2.js";
35
+ import { _ as cs, b as fs } from "../SelectField.vue_vue_type_script_setup_true_lang-BJoAkBo2.js";
36
36
  import { g as vs, m as ps } from "../options-Ba_0uLWN.js";
37
37
  import { _ as gs } from "../OtpInput.vue_vue_type_script_setup_true_lang-gp4FfWAH.js";
38
38
  import { _ as Ye } from "../PhotoViewer.vue_vue_type_script_setup_true_lang-QPCW3Xi6.js";
@@ -43,8 +43,8 @@ import { _ as Rt } from "../Modal.vue_vue_type_script_setup_true_lang-DpBb8ans.j
43
43
  import { _ as We } from "../Banner.vue_vue_type_script_setup_true_lang-DSStj_5z.js";
44
44
  import { D as Tt } from "../useWaitStatus-fsacMl4W.js";
45
45
  import { t as Et } from "../toast-CqSDTWRX.js";
46
- import { a as It } from "../AdaptivePageShell.vue_vue_type_script_setup_true_lang-DxD6JvyK.js";
47
- import { _ as Gt, a as Nt } from "../SectionList.vue_vue_type_script_setup_true_lang-CaF3LPbQ.js";
46
+ import { a as It } from "../AdaptivePageShell.vue_vue_type_script_setup_true_lang-B7qSUiee.js";
47
+ import { _ as Gt, a as Nt } from "../SectionList.vue_vue_type_script_setup_true_lang-B0p_8xQG.js";
48
48
  import { p as Kt } from "../sectionIndex-BS0ic5W7.js";
49
49
  import { u as Pt } from "../useSaveChrome-DuWm0Czf.js";
50
50
  import { matchedRouteKey as At, onBeforeRouteLeave as Ut } from "vue-router";
@@ -1,9 +1,12 @@
1
+ import type { Tone } from "../state";
1
2
  /** One choice of a select, chips, segments or cards. `Value` is what lands in the form. */
2
3
  export interface SelectOption<Value extends string | number = string | number> {
3
4
  readonly value: Value;
4
5
  readonly label: string;
5
6
  /** A caption at the end of the row (tells equal names apart). */
6
7
  readonly description?: string;
8
+ /** A status dot before the label, in the tone's colour. */
9
+ readonly dot?: Tone;
7
10
  readonly disabled?: boolean;
8
11
  /** Options with the same group are listed together, under its name, in the order the groups first appear. */
9
12
  readonly group?: string;
@@ -0,0 +1,194 @@
1
+ import { hasInjectionContext as $, inject as _, watch as O } from "vue";
2
+ import { g as j } from "./platform-q3cjODLx.js";
3
+ const k = [5, 8, 10, 15, 25, 50, 100], A = 25;
4
+ function X(e) {
5
+ const t = `defineCollection("${e.id}")`;
6
+ if (typeof e.id != "string" || e.id.trim() === "") throw new Error("defineCollection: `id` must be a non-empty string.");
7
+ if (!Number.isInteger(e.stateVersion) || e.stateVersion < 1) throw new Error(`${t}: \`stateVersion\` must be a positive integer.`);
8
+ if (typeof e.load != "function") throw new Error(`${t}: \`load\` must be a function.`);
9
+ if (typeof e.key != "function") throw new Error(`${t}: \`key\` must be a function.`);
10
+ const s = {
11
+ sorts: e.query?.sorts ? [...e.query.sorts] : null,
12
+ filters: e.query?.filters ? [...e.query.filters] : null,
13
+ views: e.query?.views ? [...e.query.views] : null,
14
+ sensitive: [...e.query?.sensitive ?? []],
15
+ pageSizes: [...e.query?.pageSizes ?? k],
16
+ search: e.query?.search ?? !0
17
+ };
18
+ if (s.pageSizes.length === 0 || s.pageSizes.some((c) => !Number.isInteger(c) || c < 1))
19
+ throw new Error(`${t}: \`query.pageSizes\` must list positive integers.`);
20
+ for (const c of s.sensitive)
21
+ if (s.filters && !s.filters.includes(c)) throw new Error(`${t}: sensitive filter "${c}" is not in \`query.filters\`.`);
22
+ const r = e.defaults ?? {}, o = r.pageSize ?? (s.pageSizes.includes(A) ? A : s.pageSizes[0]);
23
+ if (!s.pageSizes.includes(o)) throw new Error(`${t}: default page size ${o} is not one of ${s.pageSizes.join(", ")}.`);
24
+ const n = r.sort ?? null;
25
+ if (n !== null && s.sorts && !s.sorts.includes(n)) throw new Error(`${t}: default sort "${n}" is not in \`query.sorts\`.`);
26
+ const i = r.view ?? null;
27
+ if (i !== null && s.views && !s.views.includes(i)) throw new Error(`${t}: default view "${i}" is not in \`query.views\`.`);
28
+ const a = Object.fromEntries(Object.entries(r.filters ?? {}).filter(([, c]) => c !== void 0 && c !== ""));
29
+ for (const c of Object.keys(a))
30
+ if (s.filters && !s.filters.includes(c)) throw new Error(`${t}: default filter "${c}" is not in \`query.filters\`.`);
31
+ const l = r.page ?? 1;
32
+ if (!Number.isInteger(l) || l < 1) throw new Error(`${t}: default page must be a positive integer.`);
33
+ const f = r.direction ?? "asc";
34
+ if (f !== "asc" && f !== "desc") throw new Error(`${t}: default direction must be "asc" or "desc".`);
35
+ return Object.freeze({
36
+ id: e.id,
37
+ stateVersion: e.stateVersion,
38
+ load: e.load,
39
+ key: e.key,
40
+ defaults: Object.freeze({
41
+ page: l,
42
+ pageSize: o,
43
+ sort: n,
44
+ direction: f,
45
+ search: r.search ?? "",
46
+ view: i,
47
+ filters: Object.freeze(a)
48
+ }),
49
+ contract: Object.freeze(s),
50
+ migrate: e.migrate
51
+ });
52
+ }
53
+ const F = "from";
54
+ function G(e, t) {
55
+ if (typeof e == "string") {
56
+ const s = new URLSearchParams(t).toString(), r = e.indexOf("#"), o = r === -1 ? e : e.slice(0, r);
57
+ return `${o}${o.includes("?") ? "&" : "?"}${s}${r === -1 ? "" : e.slice(r)}`;
58
+ }
59
+ return { ...e, query: { ...e.query, ...t } };
60
+ }
61
+ function J(e) {
62
+ if (!$()) return;
63
+ const t = _(j, null);
64
+ t && O(
65
+ () => {
66
+ const s = t.session.state.value;
67
+ return s.status === "authenticated" ? s.user.id : null;
68
+ },
69
+ e,
70
+ { flush: "sync" }
71
+ );
72
+ }
73
+ const I = 4096, T = 200, N = 32, C = 1e6, S = /^[A-Za-z0-9_.-]{1,64}$/;
74
+ function M(e) {
75
+ let t = "";
76
+ for (const s of new TextEncoder().encode(e)) t += String.fromCharCode(s);
77
+ return btoa(t).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
78
+ }
79
+ function x(e) {
80
+ const t = e.replace(/-/g, "+").replace(/_/g, "/"), s = atob(t.padEnd(Math.ceil(t.length / 4) * 4, "="));
81
+ return new TextDecoder("utf-8", { fatal: !0 }).decode(Uint8Array.from(s, (r) => r.charCodeAt(0)));
82
+ }
83
+ const E = (e) => typeof e == "object" && e !== null && !Array.isArray(e);
84
+ function d(e, t = T) {
85
+ return typeof e == "string" && e.length <= t ? e : null;
86
+ }
87
+ function z(e, t, s) {
88
+ const { contract: r } = e, o = s ?? e.defaults, n = typeof t.p == "number" && Number.isInteger(t.p) && t.p >= 1 && t.p <= C ? t.p : o.page, i = typeof t.l == "number" && r.pageSizes.includes(t.l) ? t.l : o.pageSize;
89
+ let a = o.sort;
90
+ const l = d(t.c, 64);
91
+ l !== null && (r.sorts ? r.sorts.includes(l) : S.test(l)) && (a = l);
92
+ const f = t.d === "asc" || t.d === "desc" ? t.d : o.direction, c = d(t.s) ?? o.search;
93
+ let g = o.view;
94
+ const p = d(t.w, 64);
95
+ t.w === "" ? g = null : p !== null && (r.views ? r.views.includes(p) : S.test(p)) && (g = p);
96
+ const h = E(t.f) ? {} : { ...o.filters };
97
+ if (E(t.f)) {
98
+ let w = 0;
99
+ for (const [m, y] of Object.entries(t.f)) {
100
+ if (++w > N) break;
101
+ if (!(r.filters ? r.filters.includes(m) : S.test(m)) || r.sensitive.includes(m)) continue;
102
+ const v = typeof y == "number" || typeof y == "boolean" ? String(y) : d(y);
103
+ v !== null && v !== "" && (h[m] = v);
104
+ }
105
+ }
106
+ return { page: n, pageSize: i, sort: a, direction: f, search: c, view: g, filters: h };
107
+ }
108
+ function Z(e, t, s) {
109
+ const r = { v: e.stateVersion, p: t.page, l: t.pageSize };
110
+ t.sort && (r.c = t.sort), r.d = t.direction, (t.search || s && e.defaults.search !== s.search) && (r.s = t.search), (t.view || s && e.defaults.view !== s.view) && (r.w = t.view ?? "");
111
+ const o = Object.fromEntries(
112
+ Object.entries(t.filters).filter(([n, i]) => i !== void 0 && i !== "" && !e.contract.sensitive.includes(n))
113
+ );
114
+ return (Object.keys(o).length > 0 || Object.keys(e.defaults.filters).length > 0 || Object.keys(s?.filters ?? {}).length > 0) && (r.f = o), M(JSON.stringify(r));
115
+ }
116
+ function L(e, t, s) {
117
+ const r = t.v === void 0 ? e.stateVersion : t.v;
118
+ if (typeof r != "number" || !Number.isInteger(r)) return null;
119
+ if (r === e.stateVersion) return z(e, t, s);
120
+ const o = e.migrate?.(t, r);
121
+ return o ? z(e, o, s) : null;
122
+ }
123
+ function B(e, t, s) {
124
+ if (typeof t != "string" || t === "" || t.length > I) return null;
125
+ let r;
126
+ try {
127
+ r = JSON.parse(x(t));
128
+ } catch {
129
+ return null;
130
+ }
131
+ return E(r) ? L(e, r, s) : null;
132
+ }
133
+ function K(e) {
134
+ return JSON.stringify([
135
+ e.page,
136
+ e.pageSize,
137
+ e.sort,
138
+ e.direction,
139
+ e.search,
140
+ e.view,
141
+ Object.entries(e.filters).sort(([t], [s]) => t.localeCompare(s))
142
+ ]);
143
+ }
144
+ const b = (e) => typeof e == "object" && e !== null && !Array.isArray(e), u = (...e) => {
145
+ for (const t of e) if (typeof t == "number" && Number.isFinite(t)) return t;
146
+ return null;
147
+ };
148
+ function P(e) {
149
+ return {
150
+ // Filters first: the reserved names below always win, a filter called "page" cannot break paging.
151
+ ...e.filters,
152
+ page: e.page,
153
+ per_page: e.pageSize,
154
+ order_col: e.sort,
155
+ order_dir: e.sort ? e.direction : null,
156
+ search: e.search,
157
+ view: e.view
158
+ };
159
+ }
160
+ function V(e, t) {
161
+ const s = e.data, r = b(s) && Array.isArray(s.data), o = Array.isArray(s) ? s : r ? s.data : [], n = r ? s : {}, i = b(e.meta) ? e.meta : b(n.meta) ? n.meta : {}, a = u(n.per_page, i.per_page) ?? t.pageSize, l = u(n.total, i.total) ?? o.length, f = u(n.current_page, i.page, i.current_page) ?? t.page, c = u(n.last_page, i.last_page) ?? (l === 0 ? 0 : Math.ceil(l / Math.max(1, a))), g = u(n.from, i.from) ?? (o.length === 0 ? 0 : (f - 1) * a + 1), p = u(n.to, i.to) ?? (o.length === 0 ? 0 : g + o.length - 1), h = Array.isArray(i.views) ? i.views : Array.isArray(n.views) ? n.views : void 0;
162
+ return {
163
+ rows: o,
164
+ total: l,
165
+ page: f,
166
+ pageSize: a,
167
+ lastPage: c,
168
+ from: g,
169
+ to: p,
170
+ views: h?.filter(b).flatMap((w) => typeof w.key == "string" ? [{ key: w.key, count: u(w.count) ?? void 0 }] : []),
171
+ meta: i,
172
+ requestId: e.requestId
173
+ };
174
+ }
175
+ function Q(e, t, s = {}) {
176
+ return async (r, { signal: o }) => {
177
+ const n = await e.get(t, { query: s.params ? s.params(r) : P(r), signal: o });
178
+ return V(n, r);
179
+ };
180
+ }
181
+ export {
182
+ k as D,
183
+ F as L,
184
+ X as a,
185
+ L as b,
186
+ B as d,
187
+ Z as e,
188
+ Q as h,
189
+ P as l,
190
+ J as o,
191
+ K as q,
192
+ V as r,
193
+ G as w
194
+ };
@@ -1,4 +1,4 @@
1
- import { _ as t, h as n, j as a, i, k as o, d as r, l as d, m as u, n as y, r as l, o as I, s as f, q as p, t as A, f as c } from "../index-BykMr7eH.js";
1
+ import { _ as t, h as n, j as a, i, k as o, d as r, l as d, m as u, n as y, r as l, o as I, s as f, q as p, t as A, f as c } from "../index-By5B18A3.js";
2
2
  export {
3
3
  t as SignInAsButton,
4
4
  n as identityFeature,