@webx-ui/module-admin 0.23.5 → 0.24.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/dist/DraftsList.d.ts +21 -0
- package/dist/EditingAlerts.d.ts +114 -0
- package/dist/RenameButton.d.ts +12 -1
- package/dist/admin.d.ts +6 -1
- package/dist/editing.d.ts +204 -0
- package/dist/editingLabels.d.ts +26 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +2908 -1930
- package/dist/index.js.map +1 -1
- package/dist/merge.d.ts +61 -0
- package/dist/plural.d.ts +10 -0
- package/dist/shortcodes.d.ts +31 -0
- package/dist/style.css +1 -1
- package/dist/types.d.ts +11 -0
- package/package.json +4 -4
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** The record's name on the server's `editing/{entity}/{id}`. */
|
|
3
|
+
entity: string;
|
|
4
|
+
id: string | number | null | undefined;
|
|
5
|
+
/** Whether this reader may put a copy back. */
|
|
6
|
+
canRestore?: boolean;
|
|
7
|
+
/** Anything that changes when the record is saved or published: the list is read again. */
|
|
8
|
+
stamp?: unknown;
|
|
9
|
+
/** The screen the record is edited on, so the changed places read as the form names them. */
|
|
10
|
+
screen?: string;
|
|
11
|
+
};
|
|
12
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
13
|
+
restored: () => any;
|
|
14
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
onRestored?: (() => any) | undefined;
|
|
16
|
+
}>, {
|
|
17
|
+
screen: string;
|
|
18
|
+
canRestore: boolean;
|
|
19
|
+
stamp: undefined;
|
|
20
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { nextTick } from 'vue';
|
|
2
|
+
import { Editing } from './editing';
|
|
3
|
+
/**
|
|
4
|
+
* What an editor says about other people editing the same record, above its form.
|
|
5
|
+
*
|
|
6
|
+
* Six things, the loudest first. The record was deleted for good, with a way to copy out what was
|
|
7
|
+
* typed. The record is in the bin, with the way out of it. A conflict: both sides changed the same place, and each such
|
|
8
|
+
* place is listed with what it was, what this editor wrote and what the other side wrote, to be
|
|
9
|
+
* settled one by one — everything else has already been merged. A save that came in while this
|
|
10
|
+
* editor was open, with what it changed and an offer to pull it in before saving over it. What
|
|
11
|
+
* others did besides writing — published it, moved it, put an old version back. And,
|
|
12
|
+
* quietest, who else has the record open right now.
|
|
13
|
+
*/
|
|
14
|
+
type __VLS_Props = {
|
|
15
|
+
editing: Editing<unknown>;
|
|
16
|
+
};
|
|
17
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
18
|
+
save: () => any;
|
|
19
|
+
theirs: () => any;
|
|
20
|
+
pulled: () => any;
|
|
21
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
22
|
+
onSave?: (() => any) | undefined;
|
|
23
|
+
onTheirs?: (() => any) | undefined;
|
|
24
|
+
onPulled?: (() => any) | undefined;
|
|
25
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
26
|
+
conflictAlert: ({
|
|
27
|
+
$: import('vue').ComponentInternalInstance;
|
|
28
|
+
$data: {};
|
|
29
|
+
$props: {
|
|
30
|
+
readonly visible?: boolean | undefined;
|
|
31
|
+
readonly type?: import('@webx-ui/core').AlertType | undefined;
|
|
32
|
+
readonly variant?: import('@webx-ui/core').AlertVariant | undefined;
|
|
33
|
+
readonly title?: string | undefined;
|
|
34
|
+
readonly description?: string | undefined;
|
|
35
|
+
readonly icon?: (import('@webx-ui/core').IconName | false) | undefined;
|
|
36
|
+
readonly closable?: boolean | undefined;
|
|
37
|
+
readonly closeLabel?: string | undefined;
|
|
38
|
+
readonly live?: boolean | undefined;
|
|
39
|
+
readonly onClose?: ((event: MouseEvent) => any) | undefined | undefined;
|
|
40
|
+
readonly "onUpdate:visible"?: ((value: boolean) => any) | undefined | undefined;
|
|
41
|
+
} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps;
|
|
42
|
+
$attrs: import('vue').Attrs;
|
|
43
|
+
$refs: {
|
|
44
|
+
[x: string]: unknown;
|
|
45
|
+
};
|
|
46
|
+
$slots: Readonly<{
|
|
47
|
+
[name: string]: import('vue').Slot<any> | undefined;
|
|
48
|
+
}>;
|
|
49
|
+
$root: import('vue').ComponentPublicInstance | null;
|
|
50
|
+
$parent: import('vue').ComponentPublicInstance | null;
|
|
51
|
+
$host: Element | null;
|
|
52
|
+
$emit: ((event: "close", event: MouseEvent) => void) & ((event: "update:visible", value: boolean) => void);
|
|
53
|
+
$el: any;
|
|
54
|
+
$options: import('vue').ComponentOptionsBase<Readonly<{
|
|
55
|
+
visible?: boolean;
|
|
56
|
+
} & import('@webx-ui/core').AlertProps> & Readonly<{
|
|
57
|
+
onClose?: ((event: MouseEvent) => any) | undefined;
|
|
58
|
+
"onUpdate:visible"?: ((value: boolean) => any) | undefined;
|
|
59
|
+
}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
60
|
+
close: (event: MouseEvent) => any;
|
|
61
|
+
"update:visible": (value: boolean) => any;
|
|
62
|
+
}, string, {
|
|
63
|
+
variant: import('@webx-ui/core').AlertVariant;
|
|
64
|
+
type: import('@webx-ui/core').AlertType;
|
|
65
|
+
title: string;
|
|
66
|
+
icon: import('@webx-ui/core').IconName | false;
|
|
67
|
+
description: string;
|
|
68
|
+
closable: boolean;
|
|
69
|
+
closeLabel: string;
|
|
70
|
+
live: boolean;
|
|
71
|
+
}, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
|
|
72
|
+
beforeCreate?: (() => void) | (() => void)[];
|
|
73
|
+
created?: (() => void) | (() => void)[];
|
|
74
|
+
beforeMount?: (() => void) | (() => void)[];
|
|
75
|
+
mounted?: (() => void) | (() => void)[];
|
|
76
|
+
beforeUpdate?: (() => void) | (() => void)[];
|
|
77
|
+
updated?: (() => void) | (() => void)[];
|
|
78
|
+
activated?: (() => void) | (() => void)[];
|
|
79
|
+
deactivated?: (() => void) | (() => void)[];
|
|
80
|
+
beforeDestroy?: (() => void) | (() => void)[];
|
|
81
|
+
beforeUnmount?: (() => void) | (() => void)[];
|
|
82
|
+
destroyed?: (() => void) | (() => void)[];
|
|
83
|
+
unmounted?: (() => void) | (() => void)[];
|
|
84
|
+
renderTracked?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
|
|
85
|
+
renderTriggered?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
|
|
86
|
+
errorCaptured?: ((err: unknown, instance: import('vue').ComponentPublicInstance | null, info: string) => boolean | void) | ((err: unknown, instance: import('vue').ComponentPublicInstance | null, info: string) => boolean | void)[];
|
|
87
|
+
};
|
|
88
|
+
$forceUpdate: () => void;
|
|
89
|
+
$nextTick: typeof nextTick;
|
|
90
|
+
$watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
|
|
91
|
+
} & Readonly<{
|
|
92
|
+
variant: import('@webx-ui/core').AlertVariant;
|
|
93
|
+
type: import('@webx-ui/core').AlertType;
|
|
94
|
+
title: string;
|
|
95
|
+
icon: import('@webx-ui/core').IconName | false;
|
|
96
|
+
description: string;
|
|
97
|
+
closable: boolean;
|
|
98
|
+
closeLabel: string;
|
|
99
|
+
live: boolean;
|
|
100
|
+
}> & Omit<Readonly<{
|
|
101
|
+
visible?: boolean;
|
|
102
|
+
} & import('@webx-ui/core').AlertProps> & Readonly<{
|
|
103
|
+
onClose?: ((event: MouseEvent) => any) | undefined;
|
|
104
|
+
"onUpdate:visible"?: ((value: boolean) => any) | undefined;
|
|
105
|
+
}>, "type" | "icon" | "title" | "variant" | "closable" | "closeLabel" | "description" | "live"> & {} & import('vue').ComponentCustomProperties & {} & {
|
|
106
|
+
$slots: {
|
|
107
|
+
icon?(_: {}): any;
|
|
108
|
+
title?(_: {}): any;
|
|
109
|
+
default?(_: {}): any;
|
|
110
|
+
actions?(_: {}): any;
|
|
111
|
+
};
|
|
112
|
+
}) | null;
|
|
113
|
+
}, any>;
|
|
114
|
+
export default _default;
|
package/dist/RenameButton.d.ts
CHANGED
|
@@ -49,6 +49,9 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {
|
|
|
49
49
|
readonly autocomplete?: string | undefined;
|
|
50
50
|
readonly ariaLabel?: string | undefined;
|
|
51
51
|
readonly localized?: boolean | undefined;
|
|
52
|
+
readonly tokens?: import('@webx-ui/core').TokenOption[] | undefined;
|
|
53
|
+
readonly tokensTitle?: string | undefined;
|
|
54
|
+
readonly tokensLabel?: string | undefined;
|
|
52
55
|
readonly onChange?: ((value: string) => any) | undefined | undefined;
|
|
53
56
|
readonly "onUpdate:modelValue"?: ((value: import('@webx-ui/core').InputModelValue) => any) | undefined | undefined;
|
|
54
57
|
readonly onInput?: ((value: string) => any) | undefined | undefined;
|
|
@@ -60,7 +63,9 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {
|
|
|
60
63
|
$refs: {
|
|
61
64
|
[x: string]: unknown;
|
|
62
65
|
} & {
|
|
66
|
+
rootRef: HTMLDivElement;
|
|
63
67
|
inputRef: HTMLInputElement;
|
|
68
|
+
mirrorRef: HTMLSpanElement;
|
|
64
69
|
};
|
|
65
70
|
$slots: Readonly<{
|
|
66
71
|
[name: string]: import('vue').Slot<any> | undefined;
|
|
@@ -105,6 +110,9 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {
|
|
|
105
110
|
maxlength: number;
|
|
106
111
|
showCount: boolean;
|
|
107
112
|
localized: boolean;
|
|
113
|
+
tokens: import('@webx-ui/core').TokenOption[];
|
|
114
|
+
tokensTitle: string;
|
|
115
|
+
tokensLabel: string;
|
|
108
116
|
}, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
|
|
109
117
|
beforeCreate?: (() => void) | (() => void)[];
|
|
110
118
|
created?: (() => void) | (() => void)[];
|
|
@@ -139,6 +147,9 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {
|
|
|
139
147
|
maxlength: number;
|
|
140
148
|
showCount: boolean;
|
|
141
149
|
localized: boolean;
|
|
150
|
+
tokens: import('@webx-ui/core').TokenOption[];
|
|
151
|
+
tokensTitle: string;
|
|
152
|
+
tokensLabel: string;
|
|
142
153
|
}> & Omit<Readonly<{
|
|
143
154
|
modelValue?: import('@webx-ui/core').InputModelValue;
|
|
144
155
|
} & import('@webx-ui/core').InputProps> & Readonly<{
|
|
@@ -148,7 +159,7 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {
|
|
|
148
159
|
onClear?: (() => any) | undefined;
|
|
149
160
|
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
150
161
|
onFocus?: ((event: FocusEvent) => any) | undefined;
|
|
151
|
-
}>, "disabled" | "type" | "id" | "size" | "clearable" | "placeholder" | "status" | "ariaLabel" | "input" | "select" | "readonly" | "focus" | "blur" | "maxlength" | "showCount" | "autocomplete" | "localized"> & {
|
|
162
|
+
}>, "disabled" | "type" | "id" | "size" | "clearable" | "placeholder" | "status" | "ariaLabel" | "input" | "select" | "readonly" | "focus" | "blur" | "maxlength" | "showCount" | "autocomplete" | "localized" | "tokens" | "tokensTitle" | "tokensLabel"> & {
|
|
152
163
|
focus: () => void | undefined;
|
|
153
164
|
blur: () => void | undefined;
|
|
154
165
|
select: () => void | undefined;
|
package/dist/admin.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Patch, ScreenNode, TypeRegistry } from '@webx-ui/schema';
|
|
|
3
3
|
import { Http } from './http';
|
|
4
4
|
import { I18n } from './i18n';
|
|
5
5
|
import { ThemeController } from './theme';
|
|
6
|
-
import { AdminModule, AdminStatus, AdminUser, Manifest, NavEntry, NavGroup, PickedImage } from './types';
|
|
6
|
+
import { AdminModule, AdminStatus, AdminUser, BlockLabels, Manifest, NavEntry, NavGroup, PickedImage } from './types';
|
|
7
7
|
export interface AdminContext {
|
|
8
8
|
/** The panel's own backend. */
|
|
9
9
|
readonly http: Http;
|
|
@@ -35,6 +35,11 @@ export interface AdminContext {
|
|
|
35
35
|
* does, and a document is then shown with the addresses it was saved with.
|
|
36
36
|
*/
|
|
37
37
|
readonly assetUrls: ((paths: string[]) => Promise<Record<string, string | null>>) | null;
|
|
38
|
+
/**
|
|
39
|
+
* Names of block types and their fields, when a module installed here has a block library;
|
|
40
|
+
* fetched once for the session. Optional on the context so a hand-made one in a test needs none.
|
|
41
|
+
*/
|
|
42
|
+
readonly blockLabels?: () => Promise<BlockLabels | null>;
|
|
38
43
|
/** Ask the server what the panel is and who is signed in again. */
|
|
39
44
|
reload(): Promise<void>;
|
|
40
45
|
/**
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { ComputedRef, Ref, ShallowRef } from 'vue';
|
|
2
|
+
import { MergeChoice, MergeConflict, MergeSegment } from './merge';
|
|
3
|
+
/** Who wrote a record last, through which door, and when — the server's `changed`. */
|
|
4
|
+
export interface EditingChange {
|
|
5
|
+
author: string | null;
|
|
6
|
+
author_id: number | null;
|
|
7
|
+
/** `panel`, `mcp` (an agent) or `import`. */
|
|
8
|
+
source: string;
|
|
9
|
+
at: string | null;
|
|
10
|
+
}
|
|
11
|
+
/** Somebody else who has the record open in the panel right now. */
|
|
12
|
+
export interface EditingEditor {
|
|
13
|
+
id: number;
|
|
14
|
+
name: string;
|
|
15
|
+
since: string;
|
|
16
|
+
seen_at: string;
|
|
17
|
+
}
|
|
18
|
+
/** Where the record stands, as the heartbeat reports it. */
|
|
19
|
+
export interface EditingState {
|
|
20
|
+
status: string;
|
|
21
|
+
has_draft: boolean;
|
|
22
|
+
published_at: string | null;
|
|
23
|
+
trashed: boolean;
|
|
24
|
+
deleted_at: string | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Something that happened to the record besides its content: published, taken off the site, its
|
|
28
|
+
* draft thrown away, an old version put back, moved, put in the bin or taken out of it.
|
|
29
|
+
*/
|
|
30
|
+
export interface EditingEvent {
|
|
31
|
+
id: number;
|
|
32
|
+
kind: 'published' | 'unpublished' | 'discarded' | 'restored_version' | 'moved' | 'trashed' | 'restored' | 'purged' | string;
|
|
33
|
+
author: string | null;
|
|
34
|
+
author_id: number | null;
|
|
35
|
+
source: string;
|
|
36
|
+
at: string;
|
|
37
|
+
detail: Record<string, unknown> | null;
|
|
38
|
+
}
|
|
39
|
+
/** One copy of the draft, as `editing/{entity}/{id}/drafts` lists it. */
|
|
40
|
+
export interface DraftCopy {
|
|
41
|
+
id: number;
|
|
42
|
+
kind: 'autosave' | 'overwritten';
|
|
43
|
+
created_at: string | null;
|
|
44
|
+
author: string | null;
|
|
45
|
+
source: string;
|
|
46
|
+
fields: string[];
|
|
47
|
+
/** What this copy changed against the one before it. */
|
|
48
|
+
paths?: MergeSegment[][];
|
|
49
|
+
}
|
|
50
|
+
/** The record as the server has it now. */
|
|
51
|
+
export interface EditingVersion<T> {
|
|
52
|
+
values: T;
|
|
53
|
+
revision: string;
|
|
54
|
+
changed?: EditingChange | null;
|
|
55
|
+
}
|
|
56
|
+
export interface EditingConflict<T> {
|
|
57
|
+
/** The places both sides changed, each with its three values. */
|
|
58
|
+
conflicts: MergeConflict[];
|
|
59
|
+
/** The side each one is settled to; this editor's until somebody picks. */
|
|
60
|
+
choices: Record<string, MergeChoice>;
|
|
61
|
+
theirs: EditingVersion<T>;
|
|
62
|
+
}
|
|
63
|
+
/** Somebody else saved while this editor is open, and it has not been pulled in yet. */
|
|
64
|
+
export interface EditingIncoming<T> {
|
|
65
|
+
theirs: EditingVersion<T>;
|
|
66
|
+
paths: MergeSegment[][];
|
|
67
|
+
}
|
|
68
|
+
export interface EditingOptions<T> {
|
|
69
|
+
/** The record's name on the server's `editing/{entity}/{id}`: `pages`, `services`, `regions`. */
|
|
70
|
+
entity: string;
|
|
71
|
+
id: () => string | number | null | undefined;
|
|
72
|
+
/** The form: what this editor has now. */
|
|
73
|
+
values: Ref<T>;
|
|
74
|
+
/** The revision the form was read at; a merge moves it to the one it merged with. */
|
|
75
|
+
revision: Ref<string>;
|
|
76
|
+
/** Read the record again, for the notice's «Pull in». */
|
|
77
|
+
read: () => Promise<EditingVersion<T>>;
|
|
78
|
+
/**
|
|
79
|
+
* The server's version was taken in as the new base — after a merge, a pull or «Take theirs».
|
|
80
|
+
* The editor moves its own idea of "saved" there: whatever differs from it now is unsaved.
|
|
81
|
+
*/
|
|
82
|
+
adopt?: (theirs: EditingVersion<T>) => void;
|
|
83
|
+
/**
|
|
84
|
+
* Somebody published, unpublished, moved or restored the record: read what the editor shows
|
|
85
|
+
* around the form again — the status, the trail, the address — without touching the form.
|
|
86
|
+
*/
|
|
87
|
+
refresh?: () => void | Promise<void>;
|
|
88
|
+
/** Take the record out of the bin. Without it, the notice of the bin offers no way back. */
|
|
89
|
+
restore?: () => Promise<void>;
|
|
90
|
+
/** Whether this editor writes at all; a reader is not asked about anybody's changes. */
|
|
91
|
+
canWrite?: () => boolean;
|
|
92
|
+
/** Whether a save is on its way: a heartbeat answered meanwhile may be reporting it. */
|
|
93
|
+
busy?: () => boolean;
|
|
94
|
+
/** The screen the record is edited on, so its fields are named the way the form names them. */
|
|
95
|
+
screen?: string;
|
|
96
|
+
/** What a top-level field is called on screen, for the conflict list. */
|
|
97
|
+
field?: (name: string) => string | undefined;
|
|
98
|
+
/** What a type of block is called. */
|
|
99
|
+
block?: (type: string) => string | undefined;
|
|
100
|
+
/** Seconds between heartbeats; `false` for none (a test, a screen that is not an editor). */
|
|
101
|
+
heartbeat?: number | false;
|
|
102
|
+
}
|
|
103
|
+
export interface Editing<T> {
|
|
104
|
+
/** What the form was opened with, or last saved — the common ancestor of a merge. */
|
|
105
|
+
base: ShallowRef<T>;
|
|
106
|
+
conflict: Ref<EditingConflict<T> | null>;
|
|
107
|
+
incoming: Ref<EditingIncoming<T> | null>;
|
|
108
|
+
editors: Ref<EditingEditor[]>;
|
|
109
|
+
/** Where the record stands, by the last heartbeat. */
|
|
110
|
+
state: Ref<EditingState | null>;
|
|
111
|
+
/** What others did to the record since this editor opened it, not yet acknowledged. */
|
|
112
|
+
events: Ref<EditingEvent[]>;
|
|
113
|
+
/** The record is in the bin. */
|
|
114
|
+
trashed: ComputedRef<boolean>;
|
|
115
|
+
/** Who put it there and when, when the server knows. */
|
|
116
|
+
trashedBy: ComputedRef<EditingEvent | null>;
|
|
117
|
+
/**
|
|
118
|
+
* The record was deleted for good: who did it and when. Nothing can be saved or restored —
|
|
119
|
+
* the form keeps what it holds, to be copied out with `copyText`.
|
|
120
|
+
*/
|
|
121
|
+
gone: Ref<EditingEvent | null>;
|
|
122
|
+
/** In the bin or gone: autosave waits, and a save would only fail. */
|
|
123
|
+
stopped: ComputedRef<boolean>;
|
|
124
|
+
/**
|
|
125
|
+
* Why Save and Publish are off, for their `title`: «This is in the bin», «This was deleted for
|
|
126
|
+
* good». `undefined` while they are not — a disabled button with no reason looks frozen.
|
|
127
|
+
*/
|
|
128
|
+
blocked: ComputedRef<string | undefined>;
|
|
129
|
+
/** Whether the form holds something the server does not. */
|
|
130
|
+
unsaved: ComputedRef<boolean>;
|
|
131
|
+
/** Whether this editor can take the record out of the bin. */
|
|
132
|
+
canRestore: () => boolean;
|
|
133
|
+
/** Call with what the form now matches on the server: on opening, and after each save. */
|
|
134
|
+
opened(values: T): void;
|
|
135
|
+
/**
|
|
136
|
+
* A save was refused because the record moved. Merges it with what is in the form: `true`
|
|
137
|
+
* when nothing overlapped — the form holds both edits and the editor saves it again — and
|
|
138
|
+
* `false` when a conflict is waiting for the person.
|
|
139
|
+
*/
|
|
140
|
+
refused(theirs: EditingVersion<T>): boolean;
|
|
141
|
+
/** Pull the other side's save in before saving. Same answer as `refused`. */
|
|
142
|
+
pull(): Promise<boolean>;
|
|
143
|
+
choose(id: string, choice: MergeChoice): void;
|
|
144
|
+
/** Settle the conflict by the choices; the editor saves next. */
|
|
145
|
+
resolve(): void;
|
|
146
|
+
/** Settle every conflict their way at once. */
|
|
147
|
+
resolveTheirs(): void;
|
|
148
|
+
/**
|
|
149
|
+
* Before publishing: whether the draft on the server is still the one this editor holds. When
|
|
150
|
+
* somebody else changed it, the person is told whose changes, where and when, and chooses to
|
|
151
|
+
* publish with them or to review them first — which pulls them into the form. Answers the
|
|
152
|
+
* revision to publish with, and whether the person was already asked; `null` to stop.
|
|
153
|
+
*/
|
|
154
|
+
beforePublish(): Promise<{
|
|
155
|
+
revision: string;
|
|
156
|
+
asked: boolean;
|
|
157
|
+
} | null>;
|
|
158
|
+
/**
|
|
159
|
+
* A save or a publication failed. `true` when this was about other people — the record is in
|
|
160
|
+
* the bin, or a publication found a draft it had not seen — and a notice says so; the editor
|
|
161
|
+
* then shows nothing of its own.
|
|
162
|
+
*/
|
|
163
|
+
failed(error: unknown): Promise<boolean>;
|
|
164
|
+
/** Out of the bin. The form keeps what it holds; saving it is the caller's next step. */
|
|
165
|
+
restoreFromBin(): Promise<boolean>;
|
|
166
|
+
/** What the form holds, as text a person can paste somewhere else: each field under its name. */
|
|
167
|
+
text(): string;
|
|
168
|
+
/** That text onto the clipboard, said with a toast either way. */
|
|
169
|
+
copyText(): Promise<boolean>;
|
|
170
|
+
/** The events have been read. */
|
|
171
|
+
dismissEvents(): void;
|
|
172
|
+
/** Ask the server now rather than at the next heartbeat. */
|
|
173
|
+
check(): Promise<void>;
|
|
174
|
+
/** A place in the record as the person reads it: «Hero › Heading · EN». */
|
|
175
|
+
label(path: MergeSegment[]): string;
|
|
176
|
+
/** What a list of changed places says: «Hero › Heading, Title · EN and more». */
|
|
177
|
+
places(paths: MergeSegment[][]): string;
|
|
178
|
+
/** What happened, in a sentence: «Owner restored version 21 and published · 16:40». */
|
|
179
|
+
describe(events: EditingEvent[]): string;
|
|
180
|
+
/** A value, short, as text. */
|
|
181
|
+
preview(value: unknown): string;
|
|
182
|
+
/** Who changed it: «Anna», «Anna, through an agent». */
|
|
183
|
+
who(changed: EditingChange | null | undefined): string;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* What every drafted editor does about other people editing the same record (§ «Two editors»):
|
|
187
|
+
* merges a refused save instead of asking, asks only about a field both sides changed, says who
|
|
188
|
+
* the other side was and through which door, and keeps an ear on the server while open — who
|
|
189
|
+
* else has the record, whether somebody saved in the meantime, and what they did to it besides
|
|
190
|
+
* saving: published it, moved it, put it in the bin.
|
|
191
|
+
*
|
|
192
|
+
* The editor keeps its own save loop; this is the part that is the same in all of them.
|
|
193
|
+
*/
|
|
194
|
+
export declare function useEditing<T>(options: EditingOptions<T>): Editing<T>;
|
|
195
|
+
/** A value, short, as text: the words of a rich text without its tags, a block by its type. */
|
|
196
|
+
export declare function preview(value: unknown): string;
|
|
197
|
+
/**
|
|
198
|
+
* Every piece of text in a value with where it sits — what a person typed, to be carried out of
|
|
199
|
+
* a form whose record is gone. Rich text comes out as its words, a paragraph to a line; a block's
|
|
200
|
+
* own `key` and `type` are its shape, not anything anybody wrote.
|
|
201
|
+
*/
|
|
202
|
+
export declare function texts(value: unknown, path?: MergeSegment[]): [MergeSegment[], string][];
|
|
203
|
+
/** A sentence whose time was not known ends where the time would have been, not on a «·». */
|
|
204
|
+
export declare function timeless(text: string): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ScreenNode } from '@webx-ui/schema';
|
|
2
|
+
import { MergeSegment } from './merge';
|
|
3
|
+
export interface EditingLabelsOptions {
|
|
4
|
+
/** The screen the record is edited on: its fields are named the way the form names them. */
|
|
5
|
+
screen?: string;
|
|
6
|
+
/** What a top-level field is called, when the editor knows better than the screen. */
|
|
7
|
+
field?: (name: string) => string | undefined;
|
|
8
|
+
/** What a type of block is called, when the editor knows better than the block library. */
|
|
9
|
+
block?: (type: string) => string | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface EditingLabels {
|
|
12
|
+
/** A place in the record as the person reads it: «Hero › Eyebrow · EN». */
|
|
13
|
+
label(path: MergeSegment[]): string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Names for the places in a record, the way the person who edits it knows them.
|
|
17
|
+
*
|
|
18
|
+
* A notice that says «Hero › Below cta · EN» has turned `below_cta` into words by guessing; the
|
|
19
|
+
* block type calls that field «Text below the button», and that is the name the person looks for
|
|
20
|
+
* in the form. The screen names the record's own fields, the block library names the blocks and
|
|
21
|
+
* their fields, and a key nobody named is turned into words as a last resort.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useEditingLabels(options?: EditingLabelsOptions): EditingLabels;
|
|
24
|
+
/** Every named field of a screen tree with its label, wherever it sits — in a tab, in a card. */
|
|
25
|
+
export declare function screenLabels(root: ScreenNode[]): Map<string, string>;
|
|
26
|
+
export declare function humanize(name: string): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,18 +5,23 @@ export { createTheme, provideTheme, useTheme, themeKey, type CreateThemeOptions,
|
|
|
5
5
|
export { adminMessages } from './messages';
|
|
6
6
|
export { renderMarkdown } from './markdown';
|
|
7
7
|
export { createDates, useDates, type DateLike, type Dates } from './dates';
|
|
8
|
+
export { pluralForm, type PluralForm } from './plural';
|
|
8
9
|
export { errorText, useErrorText } from './errors';
|
|
9
10
|
export { useBodyKeys } from './keys';
|
|
11
|
+
export { changedPaths, conflictId, mergeThreeWay, sameValue, type MergeChoice, type MergeConflict, type MergeResult, type MergeSegment, } from './merge';
|
|
12
|
+
export { preview as previewValue, useEditing, type DraftCopy, type Editing, type EditingChange, type EditingConflict, type EditingEditor, type EditingIncoming, type EditingOptions, type EditingEvent, type EditingState, type EditingVersion, } from './editing';
|
|
13
|
+
export { screenLabels, useEditingLabels, type EditingLabels, type EditingLabelsOptions, } from './editingLabels';
|
|
10
14
|
export { createNotesApi, type EntityNote, type NoteAuthor, type NotesApi } from './notes';
|
|
11
15
|
export { createHistoryApi, historySubjectKey, historyValue, provideHistorySubject, useHistorySubject, type HistoryApi, type HistoryChange, type HistoryEntry, type HistoryEvent, type HistoryPage, type HistoryRun, type HistorySource, type HistorySubject, } from './history';
|
|
12
16
|
export { createLinksApi, emptyLink, type LinkCandidate, type LinkRel, type LinkSourceInfo, type LinkTarget, type LinkValue, type LinksApi, type ResolvedLink, } from './links';
|
|
17
|
+
export { forgetShortcodes, loadShortcodes, shortcodeToken, useShortcodes, type Shortcode, type ShortcodeToken, } from './shortcodes';
|
|
13
18
|
export { createHttp, readCookie, HttpError, type Http, type HttpOptions, type RequestOptions, type SendOptions, } from './http';
|
|
14
19
|
export { forgetUnfinishedUpload, MIN_CHUNK, unfinishedUploads, uploadFingerprint, useChunkedUpload, type ChunkedUpload, type ChunkedUploadOptions, type ChunkedUploadState, type UnfinishedUpload, } from './uploads';
|
|
15
20
|
export { adminTypes } from './screenTypes';
|
|
16
21
|
export { categoryRoutes, categoryEditorKey, createCategoriesApi, itemOrderMode, provideCategoryEditor, reorderItems, useCategoryEditor, useCategoryWords, useItemOrder, type CategoriesApi, type CategoriesOptions, type CategoriesPayload, type CategoryDetail, type CategoryEditorContext, type CategoryRow, type CategoryWord, type ItemOrder, type ItemOrderMode, type ItemOrderState, } from './categories';
|
|
17
22
|
export { COLLECTION_MAX_LIMIT, collectionSources, defaultMarkup, normaliseCollection, type CollectionRelated, type CollectionRelationTarget, type CollectionSourceInfo, type CollectionValue, } from './collections/api';
|
|
18
23
|
export { createRelationsApi, normaliseRelations, provideRelationOwner, relationOwnerKey, useRelationOwner, type RelationCandidate, type RelationOwner, type RelationsApi, } from './relations/api';
|
|
19
|
-
export type { AdminModule, AdminStatus, AdminUser, Manifest, ManifestModule, NavEntry, PickedImage, RowAction, ScreenAction, AppliedFilter, } from './types';
|
|
24
|
+
export type { AdminModule, AdminStatus, AdminUser, BlockLabels, Manifest, ManifestModule, NavEntry, PickedImage, RowAction, ScreenAction, AppliedFilter, } from './types';
|
|
20
25
|
export { default as AdminShell } from './AdminShell';
|
|
21
26
|
export { default as AdminNav } from './AdminNav';
|
|
22
27
|
export { default as AdminLanding } from './AdminLanding';
|
|
@@ -34,6 +39,8 @@ export { default as WxHelpButton } from './HelpButton';
|
|
|
34
39
|
export { default as WxDate } from './DateText';
|
|
35
40
|
export { default as WxNotes } from './NotesFeed';
|
|
36
41
|
export { default as WxHistory } from './HistoryFeed';
|
|
42
|
+
export { default as WxEditingAlerts } from './EditingAlerts';
|
|
43
|
+
export { default as WxDrafts } from './DraftsList';
|
|
37
44
|
export { default as WxBackupNote } from './BackupNote';
|
|
38
45
|
export { default as WxRichTextField } from './RichTextField';
|
|
39
46
|
export { default as WxLinkPicker } from './LinkPicker';
|