@wssto2/vue-core 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +2 -0
- package/dist/collection/DynamicCollection.vue.d.ts +69 -0
- package/dist/collection/RecordIdentity.vue.d.ts +1 -1
- package/dist/collection/definition.d.ts +4 -4
- package/dist/collection/dynamicColumns.d.ts +13 -0
- package/dist/collection/index.d.ts +1 -0
- package/dist/collection/index.js +195 -146
- package/dist/form/CodeField.vue.d.ts +62 -0
- package/dist/form/codeEditor.d.ts +27 -0
- package/dist/form/dynamic/DynamicForm.vue.d.ts +46 -0
- package/dist/form/dynamic/RepeatField.vue.d.ts +47 -0
- package/dist/form/dynamic/ResourceField.vue.d.ts +38 -0
- package/dist/form/dynamic/ResourcePickerList.vue.d.ts +12 -0
- package/dist/form/dynamic/RichTextField.vue.d.ts +40 -0
- package/dist/form/dynamic/localeMode.d.ts +5 -0
- package/dist/form/dynamic/resources.d.ts +34 -0
- package/dist/form/dynamic/schema.d.ts +73 -0
- package/dist/form/dynamic/validator.d.ts +30 -0
- package/dist/form/dynamic/visibility.d.ts +12 -0
- package/dist/form/index.d.ts +13 -0
- package/dist/form/index.js +2307 -1316
- package/dist/i18n/index.js +15 -15
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/resources-BZLlAtoS.js +62 -0
- package/dist/styles.css +1 -1
- package/package.json +56 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.19.0 — 2026-11-06
|
|
4
|
+
|
|
5
|
+
A code editor for forms, for the templates, components and page code a site is built from.
|
|
6
|
+
|
|
7
|
+
### New
|
|
8
|
+
- **form:** `CodeField` (CodeMirror 6, optional peers loaded when the first one shows): `v-model` string, `language: "liquid" | "html" | "css" | "javascript"`, `readonly`, `lineNumbers`, `height` (resizable), `markers: CodeMarker[]` (`{ line, column?, severity, message }` from the server's linter, drawn in the gutter and as underlines), `@save` on Ctrl/Cmd+S, a `#preview` slot that puts the app's preview beside the editor (behind a button on narrow screens). Tab indents, Esc then Tab leaves the editor. Liquid is the official `@codemirror/lang-liquid`. New types `CodeLanguage`, `CodeMarker`; new texts `core.form.code.*`. Recipe: `docs/recipes/code-field.md`.
|
|
9
|
+
- **peers:** optional `@codemirror/{state,view,commands,language,lint,lang-liquid,lang-html,lang-css,lang-javascript}` and `@lezer/highlight`.
|
|
10
|
+
- **check:consumer:** fails when the packed output imports quill or CodeMirror statically.
|
|
11
|
+
|
|
12
|
+
## 0.18.0 — 2026-11-06
|
|
13
|
+
|
|
14
|
+
Forms and lists built from a schema at run time, for content whose fields are data (site-builder's content types). The `Dynamic*` pair generates fields and columns from a typed schema; it is not a page renderer.
|
|
15
|
+
|
|
16
|
+
### New
|
|
17
|
+
- **form:** `DynamicForm` (a form from a `FormSchema`: each field kind mapped to the existing field, `visible_when` hiding, `localeMode: "perField" | "form"`, go-core's 422 field messages), `RepeatField` (repeatable group of fields, reordered with buttons), `ResourceField` (one or several ids picked through `PickerModal` over an app-supplied `list`), `RichTextField` (Quill 2, optional peer `quill`, loaded on first mount; HTML string, no sanitising in the browser), `evaluateVisibility(rule, values)` and `isEmptyValue`, `buildValidator(schema, { zod })`, and the schema types (`FormSchema`, `SchemaField`, `FieldKind`, `VisibilityRule`, `VisibilityCondition`, `ResourceSource`). New texts `core.form.dynamic.*` in the five locales. Recipe: `docs/recipes/content-forms.md`.
|
|
18
|
+
- **collection:** `DynamicCollection`: columns, sort and filters from a schema, on `defineCollection`/`CollectionPage`.
|
|
19
|
+
- **test-data:** `test-data/content/visibility.json`, the `visible_when` cases shared with servers that evaluate the same rule (copy it, do not edit the copy).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **collection:** `RowOf`, `SortOf`, `FilterOf` and `ViewOf` were `never` for every definition; they now infer from the definition, and runtime keys (`Row = Record<string, unknown>`) type-check.
|
|
23
|
+
|
|
3
24
|
## 0.17.0 — 2026-11-04
|
|
4
25
|
|
|
5
26
|
What every app built on vue-core wrote again: the phase and to-do components, date values in the date fields' own shape, a lazy locale loader, the author of a list row, "today at 14:35", typed access, two architecture rules as data, and the Playwright and vitest setup. Breaking only in that `Platform.access` is now typed by the registered permissions (see Changed).
|
package/README.md
CHANGED
|
@@ -336,6 +336,8 @@ The library's own texts are under the `core` namespace in English, Croatian, Bos
|
|
|
336
336
|
- [Shell](docs/recipes/shell.md): the default shell, contributions from features, keyboard shortcuts and their help, running inside a frame, a custom shell
|
|
337
337
|
- [App setup](docs/recipes/app-setup.md): config, session, effects, locales and flags, permissions in the UI, error sentences, startup errors
|
|
338
338
|
- [Forms](docs/recipes/forms.md): form state, fields, a record edited in group sheets, a long form, commands
|
|
339
|
+
- [Forms and lists from a schema](docs/recipes/content-forms.md): `DynamicForm`, `RepeatField`, `ResourceField`, `RichTextField`, `buildValidator`, `DynamicCollection`, `visible_when`
|
|
340
|
+
- [A code editor](docs/recipes/code-field.md): `CodeField` (CodeMirror 6): Liquid / HTML / CSS / JavaScript, linter markers, a preview beside it, the keyboard
|
|
339
341
|
- [Typed routes](docs/recipes/typed-routes.md): generated routes, `client.request`, a list from a route
|
|
340
342
|
- [Sign-in](docs/recipes/sign-in.md): go-core's identity module: the sign-in page, the session wiring, the language, the module's committed types, the dev server
|
|
341
343
|
- [Users and profile](docs/recipes/users.md): the users list and a person's record, "my profile" with the e-mail change by code, opting out, extra sections, refusals
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { RouteLocationRaw } from "vue-router";
|
|
2
|
+
import type { IconName } from "../icon";
|
|
3
|
+
import type { PageAction } from "../page";
|
|
4
|
+
import type { FormSchema } from "../form/dynamic/schema";
|
|
5
|
+
import type { RowAction } from "./columns";
|
|
6
|
+
import type { CollectionLoader, CollectionStateSource } from "./types";
|
|
7
|
+
type Row = Record<string, unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* A list page generated from a typed schema: a column per listable field, sort on the fields the backend can order by, and a
|
|
10
|
+
* filter per select, boolean and date field, all from the same schema. It is `defineCollection` + `useCollection` +
|
|
11
|
+
* `CollectionPage` with `Row = Record<string, unknown>`; the loader is yours (it receives the query with those sort and filter keys).
|
|
12
|
+
*
|
|
13
|
+
* <DynamicCollection id="content.news" :schema="schema" :load="api.entries" title="News" :record-route="(row) => `/news/${row.id}`" thumbnail="/media/{id}/thumb" />
|
|
14
|
+
*
|
|
15
|
+
* Cells: text, number, date and datetime as the standard kinds; boolean as a yes / no badge; select as a badge with the option's label;
|
|
16
|
+
* translated text in the current language; image as a picture from `thumbnail`. The first text field (or `titleField`) is the
|
|
17
|
+
* record's name and links to it. A `#cell-<key>` slot replaces any cell. The schema is read once, when the page is set up: key the
|
|
18
|
+
* component by the type to show another.
|
|
19
|
+
*
|
|
20
|
+
* Filters: a select offers its options, a boolean "yes" / "no" (the values `"true"` and `"false"`), a date the date presets.
|
|
21
|
+
*/
|
|
22
|
+
type __VLS_Props = {
|
|
23
|
+
schema: FormSchema;
|
|
24
|
+
/** The list's identity (saved views and logs use it). */
|
|
25
|
+
id: string;
|
|
26
|
+
load: CollectionLoader<Row, string, string, string>;
|
|
27
|
+
title: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
icon?: IconName;
|
|
30
|
+
actions?: readonly PageAction[];
|
|
31
|
+
/** Where a row's record lives. */
|
|
32
|
+
recordRoute?: (row: Row) => RouteLocationRaw;
|
|
33
|
+
rowActions?: (row: Row) => RowAction[];
|
|
34
|
+
/** Default: the URL's query under `q`. */
|
|
35
|
+
state?: CollectionStateSource;
|
|
36
|
+
/** The field that names the record and links to it. Default: the first text field. */
|
|
37
|
+
titleField?: string;
|
|
38
|
+
/** The columns to show, in order. Default: every listable field of the schema. */
|
|
39
|
+
columns?: readonly string[];
|
|
40
|
+
/** A URL with `{id}` for the pictures of image fields. */
|
|
41
|
+
thumbnail?: string;
|
|
42
|
+
/** The language of translated text. Default: the interface's. */
|
|
43
|
+
locale?: string;
|
|
44
|
+
};
|
|
45
|
+
declare var __VLS_6: string, __VLS_7: {
|
|
46
|
+
[x: string]: unknown;
|
|
47
|
+
};
|
|
48
|
+
type __VLS_Slots = {} & {
|
|
49
|
+
[K in NonNullable<typeof __VLS_6>]?: (props: typeof __VLS_7) => any;
|
|
50
|
+
};
|
|
51
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
52
|
+
icon: IconName;
|
|
53
|
+
state: CollectionStateSource;
|
|
54
|
+
locale: string;
|
|
55
|
+
description: string;
|
|
56
|
+
actions: readonly PageAction[];
|
|
57
|
+
columns: readonly string[];
|
|
58
|
+
thumbnail: string;
|
|
59
|
+
rowActions: (row: Row) => RowAction[];
|
|
60
|
+
recordRoute: (row: Row) => RouteLocationRaw;
|
|
61
|
+
titleField: string;
|
|
62
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
63
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
64
|
+
export default _default;
|
|
65
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
66
|
+
new (): {
|
|
67
|
+
$slots: S;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
@@ -26,8 +26,8 @@ type __VLS_Props = {
|
|
|
26
26
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
27
27
|
to: RouteLocationRaw | null;
|
|
28
28
|
subtitle: string | null;
|
|
29
|
-
subtitleSelectable: boolean;
|
|
30
29
|
highlight: string | null;
|
|
30
|
+
subtitleSelectable: boolean;
|
|
31
31
|
spread: boolean;
|
|
32
32
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
33
33
|
export default _default;
|
|
@@ -81,7 +81,7 @@ export interface CollectionDefinition<Row, Sort extends string = string, Filter
|
|
|
81
81
|
*/
|
|
82
82
|
export declare function defineCollection<Row, Sort extends string = string, Filter extends string = string, View extends string = string, Meta extends ListMeta = ListMeta>(input: CollectionDefinitionInput<Row, Sort, Filter, View, Meta>): CollectionDefinition<Row, Sort, Filter, View, Meta>;
|
|
83
83
|
/** The row, sort keys, filter keys and views of a definition, for typing code written against it. */
|
|
84
|
-
export type RowOf<D> = D extends CollectionDefinition<infer Row,
|
|
85
|
-
export type SortOf<D> = D extends CollectionDefinition<
|
|
86
|
-
export type FilterOf<D> = D extends CollectionDefinition<
|
|
87
|
-
export type ViewOf<D> = D extends CollectionDefinition<
|
|
84
|
+
export type RowOf<D> = D extends CollectionDefinition<infer Row, infer _S, infer _F, infer _V, infer _M> ? Row : never;
|
|
85
|
+
export type SortOf<D> = D extends CollectionDefinition<infer _R, infer Sort, infer _F, infer _V, infer _M> ? Sort : never;
|
|
86
|
+
export type FilterOf<D> = D extends CollectionDefinition<infer _R, infer _S, infer Filter, infer _V, infer _M> ? Filter : never;
|
|
87
|
+
export type ViewOf<D> = D extends CollectionDefinition<infer _R, infer _S, infer _F, infer View, infer _M> ? View : never;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FormSchema, SchemaField } from "../form/dynamic/schema";
|
|
2
|
+
import type { FilterDescriptor } from "./filters";
|
|
3
|
+
/** The fields shown as columns: `only` (in its order), else every listable field of the schema. */
|
|
4
|
+
export declare function listedFields(schema: FormSchema, only?: readonly string[]): SchemaField[];
|
|
5
|
+
export declare const isSortable: (field: SchemaField) => boolean;
|
|
6
|
+
export declare const isFilterable: (field: SchemaField) => boolean;
|
|
7
|
+
/** The text of a cell value: a translated text (`{ hr, en }`) in `locale`, else the first language written; anything else as it is. */
|
|
8
|
+
export declare function textOf(value: unknown, locale: string): string;
|
|
9
|
+
/** What a select-like filter offers for a field; a boolean offers yes and no as "true" and "false". */
|
|
10
|
+
export declare function optionsOf(field: SchemaField, labels: {
|
|
11
|
+
yes: string;
|
|
12
|
+
no: string;
|
|
13
|
+
}): FilterDescriptor["options"];
|
|
@@ -28,3 +28,4 @@ export type { CellSlots, CollectionSlots, RowsSlots } from "./slots";
|
|
|
28
28
|
export { createPicker } from "./picker";
|
|
29
29
|
export type { Picker, PickerOptions } from "./picker";
|
|
30
30
|
export { default as PickerModal } from "./PickerModal.vue";
|
|
31
|
+
export { default as DynamicCollection } from "./DynamicCollection.vue";
|
package/dist/collection/index.js
CHANGED
|
@@ -1,192 +1,241 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { a as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { _ as
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { _ as
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
import { d as H } from "../http-D6qOS6xs.js";
|
|
2
|
+
import { D as Fe, h as $e, l as Ie, a as je, r as Ne, b as ze } from "../http-D6qOS6xs.js";
|
|
3
|
+
import { u as J, _ as K } from "../CollectionPage.vue_vue_type_script_setup_true_lang-Dr6nFNBB.js";
|
|
4
|
+
import { a as Ve } from "../CollectionPage.vue_vue_type_script_setup_true_lang-Dr6nFNBB.js";
|
|
5
|
+
import { L as Be } from "../state-z1iPF1DT.js";
|
|
6
|
+
import { a as Ge, u as He } from "../neighbors-Dg_LU9ry.js";
|
|
7
|
+
import { r as x } from "../route-goWMxDUN.js";
|
|
8
|
+
import { b as Ke, a as Xe } from "../rowLayout-PIuD7MGo.js";
|
|
9
|
+
import { _ as Qe } from "../DataTable.vue_vue_type_script_setup_true_lang-D372wlxR.js";
|
|
10
|
+
import { defineComponent as z, openBlock as c, createElementBlock as m, Fragment as S, renderList as g, createBlock as M, unref as k, withCtx as C, normalizeClass as O, createVNode as P, createCommentVNode as X, computed as v, useSlots as Z, createSlots as Q, renderSlot as W, normalizeProps as Y, guardReactiveProps as ee, toDisplayString as _ } from "vue";
|
|
11
|
+
import { _ as R } from "../Icon.vue_vue_type_script_lang-BhhsFYwp.js";
|
|
12
|
+
import { _ as te } from "../Tooltip.vue_vue_type_script_setup_true_lang-C1C1qeBj.js";
|
|
13
|
+
import { u as ne } from "../datePresets-DB13HHHd.js";
|
|
14
|
+
import { D as Ye } from "../datePresets-DB13HHHd.js";
|
|
15
|
+
import { _ as tt, h as nt } from "../Highlight.vue_vue_type_script_setup_true_lang-DZGBmwcX.js";
|
|
16
|
+
import { t as oe } from "../resources-BZLlAtoS.js";
|
|
17
|
+
import { _ as st, c as at } from "../resources-BZLlAtoS.js";
|
|
18
|
+
import { useI18n as se } from "vue-i18n";
|
|
19
|
+
function Ae(o, t) {
|
|
20
|
+
const s = o?.authors;
|
|
21
|
+
return t == null || !Array.isArray(s) ? null : s.find((a) => a.id === t) ?? null;
|
|
18
22
|
}
|
|
19
|
-
const
|
|
20
|
-
index:
|
|
21
|
-
store:
|
|
22
|
-
delete:
|
|
23
|
-
},
|
|
24
|
-
function
|
|
23
|
+
const w = {
|
|
24
|
+
index: x("GET", "/v1/saved-views"),
|
|
25
|
+
store: x("POST", "/v1/saved-views"),
|
|
26
|
+
delete: x("DELETE", "/v1/saved-views/:id")
|
|
27
|
+
}, F = ({ id: o, name: t, state: s }) => ({ id: o, name: t, state: s });
|
|
28
|
+
function Te(o) {
|
|
25
29
|
return {
|
|
26
|
-
async list(
|
|
27
|
-
return (await
|
|
30
|
+
async list(t, { signal: s }) {
|
|
31
|
+
return (await o.request(w.index, { list: t }, { signal: s })).data.map(F);
|
|
28
32
|
},
|
|
29
|
-
async save(
|
|
30
|
-
const
|
|
31
|
-
return
|
|
33
|
+
async save(t, s, a) {
|
|
34
|
+
const r = JSON.stringify({ ...a, view: a.view || void 0 });
|
|
35
|
+
return F((await o.request(w.store, { list_key: t, name: s, state: r })).data);
|
|
32
36
|
},
|
|
33
|
-
async remove(
|
|
34
|
-
await
|
|
37
|
+
async remove(t, s) {
|
|
38
|
+
await o.request(w.delete, { id: Number(s) });
|
|
35
39
|
}
|
|
36
40
|
};
|
|
37
41
|
}
|
|
38
|
-
function
|
|
39
|
-
const
|
|
40
|
-
let
|
|
41
|
-
const
|
|
42
|
-
let
|
|
43
|
-
return
|
|
42
|
+
function Le(o = {}) {
|
|
43
|
+
const t = new Map(Object.entries(o).map(([r, n]) => [r, [...n]]));
|
|
44
|
+
let s = 1;
|
|
45
|
+
const a = (r) => {
|
|
46
|
+
let n = t.get(r);
|
|
47
|
+
return n || t.set(r, n = []), n;
|
|
44
48
|
};
|
|
45
49
|
return {
|
|
46
|
-
async list(
|
|
47
|
-
return [...
|
|
50
|
+
async list(r) {
|
|
51
|
+
return [...a(r)];
|
|
48
52
|
},
|
|
49
|
-
async save(
|
|
50
|
-
const
|
|
51
|
-
return
|
|
53
|
+
async save(r, n, f) {
|
|
54
|
+
const u = a(r), y = u.findIndex((h) => h.name === n), b = { id: y === -1 ? `view-${s++}` : u[y].id, name: n, state: f };
|
|
55
|
+
return y === -1 ? u.push(b) : u[y] = b, b;
|
|
52
56
|
},
|
|
53
|
-
async remove(
|
|
54
|
-
const
|
|
55
|
-
|
|
57
|
+
async remove(r, n) {
|
|
58
|
+
const f = a(r), u = f.findIndex((y) => y.id === n);
|
|
59
|
+
u !== -1 && f.splice(u, 1);
|
|
56
60
|
}
|
|
57
61
|
};
|
|
58
62
|
}
|
|
59
|
-
const
|
|
63
|
+
const ae = {
|
|
60
64
|
key: 0,
|
|
61
65
|
class: "flex items-center justify-center gap-1",
|
|
62
66
|
"data-test": "row-actions"
|
|
63
|
-
},
|
|
67
|
+
}, re = ["href", "target", "rel", "aria-label", "data-action"], ie = ["aria-label", "data-action", "disabled", "onClick"], $ = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus", De = /* @__PURE__ */ z({
|
|
64
68
|
__name: "RowActions",
|
|
65
69
|
props: {
|
|
66
70
|
actions: {},
|
|
67
71
|
disabled: { type: Boolean, default: !1 }
|
|
68
72
|
},
|
|
69
|
-
setup(
|
|
70
|
-
const
|
|
71
|
-
return (
|
|
72
|
-
(c(!0),
|
|
73
|
-
key:
|
|
74
|
-
text:
|
|
73
|
+
setup(o) {
|
|
74
|
+
const t = o, s = (a) => a.tone === "critical" ? "text-status-danger-content hover:bg-status-danger-surface" : "text-content-link hover:bg-tint-soft";
|
|
75
|
+
return (a, r) => t.actions.length > 0 ? (c(), m("div", ae, [
|
|
76
|
+
(c(!0), m(S, null, g(t.actions, (n) => (c(), M(k(te), {
|
|
77
|
+
key: n.key,
|
|
78
|
+
text: n.label,
|
|
75
79
|
side: "left"
|
|
76
80
|
}, {
|
|
77
|
-
default:
|
|
78
|
-
|
|
81
|
+
default: C(() => [
|
|
82
|
+
n.href && !t.disabled ? (c(), m("a", {
|
|
79
83
|
key: 0,
|
|
80
|
-
href:
|
|
81
|
-
target:
|
|
82
|
-
rel:
|
|
83
|
-
"aria-label":
|
|
84
|
-
"data-action":
|
|
85
|
-
class:
|
|
84
|
+
href: n.href,
|
|
85
|
+
target: n.external ? "_blank" : void 0,
|
|
86
|
+
rel: n.external ? "noopener" : void 0,
|
|
87
|
+
"aria-label": n.label,
|
|
88
|
+
"data-action": n.key,
|
|
89
|
+
class: O(["inline-flex rounded-md p-1.5 transition-colors", [s(n), $]])
|
|
86
90
|
}, [
|
|
87
|
-
|
|
88
|
-
name:
|
|
91
|
+
P(k(R), {
|
|
92
|
+
name: n.icon,
|
|
89
93
|
size: 18
|
|
90
94
|
}, null, 8, ["name"])
|
|
91
|
-
], 10,
|
|
95
|
+
], 10, re)) : (c(), m("button", {
|
|
92
96
|
key: 1,
|
|
93
97
|
type: "button",
|
|
94
|
-
"aria-label":
|
|
95
|
-
"data-action":
|
|
96
|
-
disabled:
|
|
97
|
-
class:
|
|
98
|
-
onClick: (
|
|
98
|
+
"aria-label": n.label,
|
|
99
|
+
"data-action": n.key,
|
|
100
|
+
disabled: t.disabled,
|
|
101
|
+
class: O(["inline-flex cursor-pointer rounded-md p-1.5 transition-colors disabled:pointer-events-none disabled:opacity-40", [s(n), $]]),
|
|
102
|
+
onClick: (f) => n.onSelect?.()
|
|
99
103
|
}, [
|
|
100
|
-
|
|
101
|
-
name:
|
|
104
|
+
P(k(R), {
|
|
105
|
+
name: n.icon,
|
|
102
106
|
size: 18
|
|
103
107
|
}, null, 8, ["name"])
|
|
104
|
-
], 10,
|
|
108
|
+
], 10, ie))
|
|
105
109
|
]),
|
|
106
110
|
_: 2
|
|
107
111
|
}, 1032, ["text"]))), 128))
|
|
108
|
-
])) :
|
|
112
|
+
])) : X("", !0);
|
|
109
113
|
}
|
|
110
|
-
});
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
}), le = ["text", "number", "boolean", "select", "multi_select", "date", "datetime", "image", "document", "gallery"], ce = ["text", "number", "boolean", "select", "date", "datetime"], de = ["select", "boolean", "date", "datetime"];
|
|
115
|
+
function ue(o, t) {
|
|
116
|
+
return t ? t.flatMap((s) => o.fields.filter((a) => a.key === s)) : o.fields.filter((s) => le.includes(s.kind));
|
|
117
|
+
}
|
|
118
|
+
const I = (o) => ce.includes(o.kind) && !o.translatable, j = (o) => de.includes(o.kind) && !o.translatable;
|
|
119
|
+
function N(o, t) {
|
|
120
|
+
if (o == null) return "";
|
|
121
|
+
if (typeof o == "object" && !Array.isArray(o)) {
|
|
122
|
+
const s = o, a = s[t];
|
|
123
|
+
return typeof a == "string" && a !== "" ? a : Object.values(s).find((r) => typeof r == "string" && r !== "") ?? "";
|
|
117
124
|
}
|
|
118
|
-
return
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
e = o, a.value = { open: !0, options: s ?? {} };
|
|
123
|
-
});
|
|
124
|
-
},
|
|
125
|
-
select: (s) => i(s),
|
|
126
|
-
cancel: () => i(null)
|
|
127
|
-
};
|
|
125
|
+
return String(o);
|
|
126
|
+
}
|
|
127
|
+
function me(o, t) {
|
|
128
|
+
return o.kind === "boolean" ? [{ value: "true", label: t.yes }, { value: "false", label: t.no }] : (o.options ?? []).map((s) => ({ value: s.value, label: s.label }));
|
|
128
129
|
}
|
|
129
|
-
const
|
|
130
|
-
__name: "
|
|
130
|
+
const ye = { key: 0 }, pe = ["src"], fe = { key: 2 }, ke = { key: 3 }, be = { key: 4 }, Oe = /* @__PURE__ */ z({
|
|
131
|
+
__name: "DynamicCollection",
|
|
131
132
|
props: {
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
schema: {},
|
|
134
|
+
id: {},
|
|
135
|
+
load: {},
|
|
136
|
+
title: {},
|
|
134
137
|
description: { default: void 0 },
|
|
135
|
-
|
|
138
|
+
icon: { default: void 0 },
|
|
139
|
+
actions: { default: () => [] },
|
|
140
|
+
recordRoute: { type: Function, default: void 0 },
|
|
141
|
+
rowActions: { type: Function, default: void 0 },
|
|
142
|
+
state: { default: () => ({ kind: "url", key: "q" }) },
|
|
143
|
+
titleField: { default: void 0 },
|
|
144
|
+
columns: { default: void 0 },
|
|
145
|
+
thumbnail: { default: void 0 },
|
|
146
|
+
locale: { default: void 0 }
|
|
136
147
|
},
|
|
137
|
-
setup(
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
148
|
+
setup(o) {
|
|
149
|
+
const t = o, { t: s, locale: a } = se(), r = v(() => t.locale ?? a.value), n = ue(t.schema, t.columns), f = t.titleField ?? n.find((e) => e.kind === "text")?.key, u = v(() => ({ yes: s("core.form.yes"), no: s("core.form.no") })), y = H({
|
|
150
|
+
id: t.id,
|
|
151
|
+
stateVersion: 1,
|
|
152
|
+
load: t.load,
|
|
153
|
+
key: (e) => e.id,
|
|
154
|
+
query: { sorts: n.filter(I).map((e) => e.key), filters: n.filter(j).map((e) => e.key) }
|
|
155
|
+
}), b = new Map(n.filter((e) => e.kind === "date" || e.kind === "datetime").map((e) => [e.key, ne(e.key, e.label)])), h = v(() => n.filter(j).map((e) => b.get(e.key)?.value ?? { key: e.key, label: e.label, type: "select", options: me(e, u.value) })), E = (e, i) => e.options?.find((l) => l.value === i)?.label ?? String(i ?? ""), A = v(() => n.map((e) => {
|
|
156
|
+
const i = { key: e.key, label: e.label, ...I(e) ? { sort: e.key } : {} };
|
|
157
|
+
if (e.key === f) return { ...i, kind: "identity", title: (l) => N(l[e.key], r.value) };
|
|
158
|
+
switch (e.kind) {
|
|
159
|
+
case "number":
|
|
160
|
+
return { ...i, kind: "number" };
|
|
161
|
+
case "date":
|
|
162
|
+
return { ...i, kind: "timestamp", precision: "date" };
|
|
163
|
+
case "datetime":
|
|
164
|
+
return { ...i, kind: "timestamp", precision: "dateTime" };
|
|
165
|
+
case "boolean":
|
|
166
|
+
return { ...i, kind: "badge", tone: (l) => l[e.key] === !0 ? "positive" : "neutral", text: (l) => l[e.key] === !0 ? u.value.yes : u.value.no };
|
|
167
|
+
case "select":
|
|
168
|
+
return { ...i, kind: "badge", tone: () => "neutral", text: (l) => E(e, l[e.key]) };
|
|
169
|
+
case "text":
|
|
170
|
+
return e.translatable ? { ...i, kind: "custom" } : { ...i, kind: "text" };
|
|
171
|
+
default:
|
|
172
|
+
return { ...i, kind: "custom" };
|
|
173
|
+
}
|
|
174
|
+
})), V = J(y, {
|
|
175
|
+
columns: A,
|
|
176
|
+
filters: h,
|
|
177
|
+
state: t.state,
|
|
178
|
+
...t.recordRoute ? { recordRoute: t.recordRoute } : {}
|
|
179
|
+
}), T = (e) => `cell-${e.replace(/\./g, "_")}`, L = Z(), q = v(() => A.value.filter((e) => e.kind === "custom" && !(T(e.key) in L))), B = () => Object.keys(L), U = (e) => n.find((i) => i.key === e), D = (e) => Array.isArray(e) ? e : [];
|
|
180
|
+
return (e, i) => (c(), M(K, {
|
|
181
|
+
collection: k(V),
|
|
182
|
+
title: t.title,
|
|
183
|
+
description: t.description,
|
|
184
|
+
icon: t.icon,
|
|
185
|
+
actions: t.actions,
|
|
186
|
+
"row-actions": t.rowActions
|
|
187
|
+
}, Q({ _: 2 }, [
|
|
188
|
+
g(B(), (l) => ({
|
|
189
|
+
name: l,
|
|
190
|
+
fn: C((p) => [
|
|
191
|
+
W(e.$slots, l, Y(ee(p ?? {})))
|
|
192
|
+
])
|
|
193
|
+
})),
|
|
194
|
+
g(q.value, (l) => ({
|
|
195
|
+
name: T(l.key),
|
|
196
|
+
fn: C(({ item: p }) => [
|
|
197
|
+
(c(!0), m(S, null, g([U(l.key)], (d) => (c(), m(S, {
|
|
198
|
+
key: d.key
|
|
199
|
+
}, [
|
|
200
|
+
d.kind === "text" ? (c(), m("span", ye, _(k(N)(p[d.key], r.value)), 1)) : d.kind === "image" && t.thumbnail && p[d.key] != null ? (c(), m("img", {
|
|
201
|
+
key: 1,
|
|
202
|
+
src: k(oe)({ thumbnail: t.thumbnail }, p[d.key]),
|
|
203
|
+
alt: "",
|
|
204
|
+
class: "size-10 rounded object-cover",
|
|
205
|
+
loading: "lazy"
|
|
206
|
+
}, null, 8, pe)) : d.kind === "gallery" ? (c(), m("span", fe, _(D(p[d.key]).length || ""), 1)) : d.kind === "multi_select" ? (c(), m("span", ke, _(D(p[d.key]).map((G) => E(d, G)).join(", ")), 1)) : (c(), m("span", be, _(p[d.key] ?? ""), 1))
|
|
207
|
+
], 64))), 128))
|
|
208
|
+
])
|
|
209
|
+
}))
|
|
210
|
+
]), 1032, ["collection", "title", "description", "icon", "actions", "row-actions"]));
|
|
163
211
|
}
|
|
164
212
|
});
|
|
165
213
|
export {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
214
|
+
Ke as CollectionCell,
|
|
215
|
+
K as CollectionPage,
|
|
216
|
+
Ve as CollectionTable,
|
|
217
|
+
Ye as DATE_PRESETS,
|
|
218
|
+
Fe as DEFAULT_PAGE_SIZES,
|
|
219
|
+
Qe as DataTable,
|
|
220
|
+
Oe as DynamicCollection,
|
|
221
|
+
tt as Highlight,
|
|
222
|
+
Be as LIST_CONTEXT_PARAM,
|
|
223
|
+
st as PickerModal,
|
|
224
|
+
Xe as RecordIdentity,
|
|
225
|
+
De as RowActions,
|
|
226
|
+
Ae as authorOf,
|
|
227
|
+
Le as createMemorySavedViews,
|
|
228
|
+
at as createPicker,
|
|
229
|
+
H as defineCollection,
|
|
230
|
+
nt as highlightParts,
|
|
231
|
+
$e as httpList,
|
|
232
|
+
Ie as listLoader,
|
|
233
|
+
je as listParams,
|
|
234
|
+
Ne as readListPage,
|
|
235
|
+
ze as routeListLoader,
|
|
236
|
+
Te as serverSavedViews,
|
|
237
|
+
J as useCollection,
|
|
238
|
+
Ge as useCollectionBack,
|
|
239
|
+
He as useCollectionNeighbors,
|
|
240
|
+
ne as useDatePresetFilter
|
|
192
241
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type CodeLanguage, type CodeMarker } from "./codeEditor";
|
|
2
|
+
import { type FieldProps, type FieldSlots } from "./field";
|
|
3
|
+
/**
|
|
4
|
+
* Source code: Liquid templates, HTML, CSS or JavaScript, with highlighting, line numbers and the findings of a linter. The value
|
|
5
|
+
* is the text ("" when empty). The editor is CodeMirror 6, optional peer dependencies loaded when the field first shows
|
|
6
|
+
* (see `loadCodeEditor`); an application that never shows this field never loads them.
|
|
7
|
+
*
|
|
8
|
+
* `markers` come from the server's linter (the browser checks nothing): each is drawn in the gutter and as an underline on its
|
|
9
|
+
* line, with the message on hover. `@save` fires on Ctrl/Cmd+S. Tab indents; Esc, then Tab, moves on to the next control.
|
|
10
|
+
* Give the `preview` slot (an iframe of the rendered page) and the editor sits beside it, below it on narrow screens behind a button.
|
|
11
|
+
*
|
|
12
|
+
* <CodeField v-model="form.body" language="liquid" :markers="lint" label="Template" @save="save">
|
|
13
|
+
* <template #preview><iframe :src="previewUrl" title="Preview" class="size-full" /></template>
|
|
14
|
+
* </CodeField>
|
|
15
|
+
*/
|
|
16
|
+
type __VLS_Props = FieldProps & {
|
|
17
|
+
modelValue?: string;
|
|
18
|
+
language?: CodeLanguage;
|
|
19
|
+
/** Visible and selectable, not editable (a read-only viewer of a published version). */
|
|
20
|
+
readonly?: boolean;
|
|
21
|
+
lineNumbers?: boolean;
|
|
22
|
+
/** The height of the editor; the user can drag it taller (any CSS length). */
|
|
23
|
+
height?: string;
|
|
24
|
+
markers?: readonly CodeMarker[];
|
|
25
|
+
};
|
|
26
|
+
type __VLS_Slots = FieldSlots & {
|
|
27
|
+
/** The app's preview of the code; the editor goes beside it. */
|
|
28
|
+
preview?: () => unknown;
|
|
29
|
+
};
|
|
30
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {
|
|
31
|
+
focus: () => void | undefined;
|
|
32
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
33
|
+
save: () => any;
|
|
34
|
+
"update:modelValue": (source: string) => any;
|
|
35
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
36
|
+
onSave?: (() => any) | undefined;
|
|
37
|
+
"onUpdate:modelValue"?: ((source: string) => any) | undefined;
|
|
38
|
+
}>, {
|
|
39
|
+
disabled: boolean;
|
|
40
|
+
name: string;
|
|
41
|
+
label: string;
|
|
42
|
+
error: string;
|
|
43
|
+
required: boolean;
|
|
44
|
+
height: string;
|
|
45
|
+
presentation: "control" | "value";
|
|
46
|
+
modelValue: string;
|
|
47
|
+
labelHidden: boolean;
|
|
48
|
+
hint: string;
|
|
49
|
+
editable: boolean;
|
|
50
|
+
lockedReason: string;
|
|
51
|
+
readonly: boolean;
|
|
52
|
+
language: CodeLanguage;
|
|
53
|
+
lineNumbers: boolean;
|
|
54
|
+
markers: readonly CodeMarker[];
|
|
55
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
56
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
57
|
+
export default _default;
|
|
58
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
59
|
+
new (): {
|
|
60
|
+
$slots: S;
|
|
61
|
+
};
|
|
62
|
+
};
|