@mdbase-dev/ui 0.1.0-beta.126 → 0.1.0-beta.147
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/README.md +159 -0
- package/css/collections.css +978 -0
- package/css/controls.css +26 -1
- package/css/screens.css +44 -2
- package/dist/AppSwitcher.js +187 -33
- package/dist/Checkbox.d.ts +14 -0
- package/dist/Checkbox.js +32 -0
- package/dist/CommandPalette.d.ts +4 -2
- package/dist/CommandPalette.js +275 -103
- package/dist/Dialog.js +72 -25
- package/dist/Feedback.js +763 -229
- package/dist/FeedbackMarkup.d.ts +1 -1
- package/dist/FeedbackMarkup.js +326 -125
- package/dist/FeedbackVerification.js +115 -68
- package/dist/SaveNotice.js +71 -28
- package/dist/Select.js +183 -135
- package/dist/SelectList.js +59 -14
- package/dist/ThemeSelect.js +55 -4
- package/dist/apps.d.ts +1 -0
- package/dist/apps.js +50 -29
- package/dist/brand.js +251 -68
- package/dist/codemirror.js +116 -87
- package/dist/collections/CollectionGate.d.ts +52 -0
- package/dist/collections/CollectionGate.js +456 -0
- package/dist/collections/CollectionSaveWarning.d.ts +10 -0
- package/dist/collections/CollectionSaveWarning.js +28 -0
- package/dist/collections/CollectionSwitcher.d.ts +26 -0
- package/dist/collections/CollectionSwitcher.js +579 -0
- package/dist/collections/SetupReview.d.ts +9 -0
- package/dist/collections/SetupReview.js +175 -0
- package/dist/collections/copy.d.ts +100 -0
- package/dist/collections/copy.js +937 -0
- package/dist/collections/dialogs.d.ts +27 -0
- package/dist/collections/dialogs.js +169 -0
- package/dist/collections/model.d.ts +146 -0
- package/dist/collections/model.js +337 -0
- package/dist/collections/mount.d.ts +18 -0
- package/dist/collections/mount.js +56 -0
- package/dist/collections/parts.d.ts +86 -0
- package/dist/collections/parts.js +439 -0
- package/dist/collections/testing.d.ts +19 -0
- package/dist/collections/testing.js +39 -0
- package/dist/collections/use-collection-ui.d.ts +140 -0
- package/dist/collections/use-collection-ui.js +236 -0
- package/dist/collections.d.ts +19 -0
- package/dist/collections.js +13 -0
- package/dist/feedback-data.d.ts +13 -12
- package/dist/feedback-data.js +365 -168
- package/dist/flock.d.ts +63 -0
- package/dist/flock.js +140 -0
- package/dist/i18n.d.ts +6 -0
- package/dist/i18n.js +71 -0
- package/dist/locales/de/messages.json +1 -0
- package/dist/locales/en/messages.json +1 -0
- package/dist/locales/es/messages.json +1 -0
- package/dist/locales/fr/messages.json +1 -0
- package/dist/locales/it/messages.json +1 -0
- package/dist/locales/ja/messages.json +1 -0
- package/dist/locales/ko/messages.json +1 -0
- package/dist/locales/pt/messages.json +1 -0
- package/dist/locales/ru/messages.json +1 -0
- package/dist/locales/zh/messages.json +1 -0
- package/dist/mark-activity.js +82 -75
- package/dist/permission-selection.js +27 -17
- package/dist/popover.js +138 -130
- package/dist/screens.d.ts +20 -3
- package/dist/screens.js +275 -6
- package/dist/select-model.js +34 -28
- package/dist/text-diff.d.ts +1 -0
- package/dist/text-diff.js +106 -74
- package/dist/theme.js +34 -40
- package/package.json +52 -7
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { Mdbase, MdbaseProblem } from "@mdbase-dev/sdk";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
import { type CollectionCopy } from "./copy.js";
|
|
4
|
+
import { type CollectionNotice, type CollectionRow, type CollectionView, type ProblemControl } from "./model.js";
|
|
5
|
+
/** The only app-specific input: what the app is called, and its mark. */
|
|
6
|
+
export interface CollectionAppIdentity {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly mark?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export type LeaveIntent = "switch" | "add" | "choose_another" | "sign_out";
|
|
11
|
+
/** A collection the app lists itself (one the SDK doesn't), in an app section. */
|
|
12
|
+
export interface CollectionSectionItem {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
/** A second line under the name: where it lives, or which account. */
|
|
16
|
+
readonly detail?: string | null | undefined;
|
|
17
|
+
/** Open in the app now. With `renderAppCollection`, the gate shows the app instead of its screens. */
|
|
18
|
+
readonly current?: boolean | undefined;
|
|
19
|
+
/** Listed but not selectable; say why in `detail`. */
|
|
20
|
+
readonly disabled?: boolean | undefined;
|
|
21
|
+
/** The row's menu, like an SDK collection's: shown when there is at least one. */
|
|
22
|
+
readonly actions?: readonly CollectionSectionItemAction[] | undefined;
|
|
23
|
+
}
|
|
24
|
+
/** An entry in an app section item's row menu. */
|
|
25
|
+
export interface CollectionSectionItemAction {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly label: string;
|
|
28
|
+
/** Runs in the click, after the menu closes and focus is back on the row's menu button. */
|
|
29
|
+
readonly onSelect: (item: CollectionSectionItem, context: CollectionSectionItemActionContext) => void;
|
|
30
|
+
/** Destructive: shown in the danger colour. Confirm before acting, for example with `confirmDelete`. */
|
|
31
|
+
readonly danger?: boolean | undefined;
|
|
32
|
+
readonly disabled?: boolean | undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* How the delete dialog ended: `deleted`; `cancelled` with no attempt; `failed`
|
|
36
|
+
* when the person closed it after a delete was refused.
|
|
37
|
+
*/
|
|
38
|
+
export type DeleteCollectionOutcome = "deleted" | "cancelled" | "failed";
|
|
39
|
+
/** What a section item action can ask of the screen that shows its menu. */
|
|
40
|
+
export interface CollectionSectionItemActionContext {
|
|
41
|
+
/**
|
|
42
|
+
* Open `DeleteCollectionDialog` for the item: the person types its name, then
|
|
43
|
+
* the SDK deletes it by the item's id. `onClose` gets the outcome.
|
|
44
|
+
*/
|
|
45
|
+
readonly confirmDelete: (onClose?: (outcome: DeleteCollectionOutcome) => void) => void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A titled group of app-listed collections, shown after "Your collections" on
|
|
49
|
+
* the gate's choosing and signed-out screens and in the switcher.
|
|
50
|
+
*/
|
|
51
|
+
export interface CollectionSection {
|
|
52
|
+
readonly id: string;
|
|
53
|
+
readonly title: string;
|
|
54
|
+
readonly items: readonly CollectionSectionItem[];
|
|
55
|
+
/** Open an item. Runs in the click, after `onBeforeLeave("switch")` when something else is open. */
|
|
56
|
+
readonly onSelect: (item: CollectionSectionItem) => void;
|
|
57
|
+
/** Close the open item: the person chose another collection or went back to the list. */
|
|
58
|
+
readonly onClose?: ((item: CollectionSectionItem) => void) | undefined;
|
|
59
|
+
/** Shown when there are no items. Without it an empty section is hidden. */
|
|
60
|
+
readonly empty?: string | undefined;
|
|
61
|
+
}
|
|
62
|
+
/** The app section item that is open, if any. */
|
|
63
|
+
export interface OpenSectionItem {
|
|
64
|
+
readonly section: CollectionSection;
|
|
65
|
+
readonly item: CollectionSectionItem;
|
|
66
|
+
}
|
|
67
|
+
export interface CollectionUiOptions {
|
|
68
|
+
/** The app's entry from `createMdbase`. */
|
|
69
|
+
readonly mdbase: Mdbase;
|
|
70
|
+
readonly app: CollectionAppIdentity;
|
|
71
|
+
/**
|
|
72
|
+
* Asked before anything that leaves the open collection. Return false to stay.
|
|
73
|
+
* Return a promise to ask first (an unsaved-work dialog): resolve it from that
|
|
74
|
+
* dialog's own click, and the shared UI continues in the same task, so a
|
|
75
|
+
* Connect window it opens still counts as the person's gesture.
|
|
76
|
+
*/
|
|
77
|
+
readonly onBeforeLeave?: ((intent: LeaveIntent) => boolean | Promise<boolean>) | undefined;
|
|
78
|
+
/** @deprecated Presentation-only compatibility option; the single Add entry always uses the SDK chooser. */
|
|
79
|
+
readonly allowPrivate?: boolean | undefined;
|
|
80
|
+
/** Offer "Delete collection…" to owners. Default false. */
|
|
81
|
+
readonly allowDelete?: boolean | undefined;
|
|
82
|
+
/** Replacement or translated copy by key. */
|
|
83
|
+
readonly copy?: Partial<CollectionCopy> | undefined;
|
|
84
|
+
/** App-listed collections, in sections after the SDK's own list. */
|
|
85
|
+
readonly sections?: readonly CollectionSection[] | undefined;
|
|
86
|
+
/** A second line for an SDK collection row (where it lives, which account), from the row and its SDK entry. */
|
|
87
|
+
readonly rowDetail?: ((row: CollectionRow) => string | null | undefined) | undefined;
|
|
88
|
+
}
|
|
89
|
+
/** `add_private` remains available to legacy track callers; both add APIs now emit `add`. */
|
|
90
|
+
export type CollectionActionName = "sign_in" | "add" | "add_private" | "approve" | "select" | "choose_another" | "assess" | "start" | "sign_out" | "setup";
|
|
91
|
+
export interface CollectionUi {
|
|
92
|
+
readonly view: CollectionView;
|
|
93
|
+
readonly copy: CollectionCopy;
|
|
94
|
+
readonly say: (key: keyof CollectionCopy, values?: Readonly<Record<string, string>>) => string;
|
|
95
|
+
readonly options: CollectionUiOptions;
|
|
96
|
+
/** The running action, if any. Its controls stay focusable but inert. */
|
|
97
|
+
readonly busy: CollectionActionName | null;
|
|
98
|
+
/** The last failed action's SDK description, while the phase is unchanged. */
|
|
99
|
+
readonly error: CollectionNotice | null;
|
|
100
|
+
/** Set when sign-out found unsaved changes: the SDK's copy for the confirm. */
|
|
101
|
+
readonly signOutPrompt: MdbaseProblem | null;
|
|
102
|
+
/** The open app section item, which takes the place of the SDK's current collection. */
|
|
103
|
+
readonly appOpen: OpenSectionItem | null;
|
|
104
|
+
readonly actions: CollectionActions;
|
|
105
|
+
}
|
|
106
|
+
export interface CollectionActions {
|
|
107
|
+
signIn(): void;
|
|
108
|
+
addCollection(): void;
|
|
109
|
+
/** @deprecated Use addCollection. Both names open the same SDK chooser. */
|
|
110
|
+
addPrivateCollection(): void;
|
|
111
|
+
approve(collectionId: string | null): void;
|
|
112
|
+
select(collectionId: string): void;
|
|
113
|
+
/** Open an app section item, closing whatever app item was open. */
|
|
114
|
+
selectItem(section: CollectionSection, item: CollectionSectionItem): void;
|
|
115
|
+
/** Back to the list: closes the open app item, or the SDK's collection. */
|
|
116
|
+
chooseAnother(): void;
|
|
117
|
+
/** Open the Connect window again for the authorization in progress. */
|
|
118
|
+
reopen(): void;
|
|
119
|
+
/** Abandon the authorization this page started. */
|
|
120
|
+
cancel(): void;
|
|
121
|
+
assess(): void;
|
|
122
|
+
start(): void;
|
|
123
|
+
signOut(): void;
|
|
124
|
+
confirmSignOut(): void;
|
|
125
|
+
dismissSignOut(): void;
|
|
126
|
+
/** Run a problem's own control. `set_up` goes to `onSetUp`. */
|
|
127
|
+
perform(control: ProblemControl, onSetUp?: () => void): void;
|
|
128
|
+
/** Track an app-ui call that is not a button above (setup), so errors show the same way. */
|
|
129
|
+
track(name: CollectionActionName, call: () => Promise<unknown>): Promise<unknown>;
|
|
130
|
+
}
|
|
131
|
+
/** The first current item across the app's sections. */
|
|
132
|
+
export declare function appOpenItem(sections: readonly CollectionSection[] | undefined): OpenSectionItem | null;
|
|
133
|
+
/**
|
|
134
|
+
* Start the front door once it is rendered, while it has not started. `start()`
|
|
135
|
+
* is safe to call again; this also skips calls while one is in flight, so
|
|
136
|
+
* several gates and StrictMode's double effects make one call.
|
|
137
|
+
*/
|
|
138
|
+
export declare function useAutoStart(mdbase: Mdbase, enabled?: boolean): void;
|
|
139
|
+
/** Subscribe to the app's mdbase entry and get its view plus gesture-safe actions. */
|
|
140
|
+
export declare function useCollectionUi(options: CollectionUiOptions): CollectionUi;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { useLocaleRevision } from "../i18n.js";
|
|
2
|
+
import { describeError } from "@mdbase-dev/sdk/describe";
|
|
3
|
+
import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { defaultCollectionCopy, fill } from "./copy.js";
|
|
5
|
+
import { actionNotice, collectionView } from "./model.js";
|
|
6
|
+
const popupActions = new Set(["sign_in", "add", "add_private", "approve"]);
|
|
7
|
+
/** The first current item across the app's sections. */
|
|
8
|
+
export function appOpenItem(sections) {
|
|
9
|
+
for (const section of sections ?? []) {
|
|
10
|
+
const item = section.items.find(candidate => candidate.current);
|
|
11
|
+
if (item) return {
|
|
12
|
+
section,
|
|
13
|
+
item
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const starting = new WeakSet();
|
|
19
|
+
/**
|
|
20
|
+
* Start the front door once it is rendered, while it has not started. `start()`
|
|
21
|
+
* is safe to call again; this also skips calls while one is in flight, so
|
|
22
|
+
* several gates and StrictMode's double effects make one call.
|
|
23
|
+
*/
|
|
24
|
+
export function useAutoStart(mdbase, enabled = true) {
|
|
25
|
+
const notStarted = useSyncExternalStore(mdbase.subscribe, () => mdbase.getSnapshot().status === "not_started", () => false);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!enabled || !notStarted || starting.has(mdbase)) return;
|
|
28
|
+
starting.add(mdbase);
|
|
29
|
+
const done = () => {
|
|
30
|
+
starting.delete(mdbase);
|
|
31
|
+
};
|
|
32
|
+
// A failed start shows as the snapshot's problem.
|
|
33
|
+
new Promise(resolve => {
|
|
34
|
+
resolve(mdbase.start());
|
|
35
|
+
}).then(done, done);
|
|
36
|
+
}, [mdbase, enabled, notStarted]);
|
|
37
|
+
}
|
|
38
|
+
/** Subscribe to the app's mdbase entry and get its view plus gesture-safe actions. */
|
|
39
|
+
export function useCollectionUi(options) {
|
|
40
|
+
const {
|
|
41
|
+
mdbase,
|
|
42
|
+
app
|
|
43
|
+
} = options;
|
|
44
|
+
const snapshot = useSyncExternalStore(mdbase.subscribe, mdbase.getSnapshot, mdbase.getSnapshot);
|
|
45
|
+
const localeRevision = useLocaleRevision();
|
|
46
|
+
const copy = useMemo(() => ({
|
|
47
|
+
...defaultCollectionCopy,
|
|
48
|
+
...options.copy
|
|
49
|
+
}), [options.copy, localeRevision]);
|
|
50
|
+
const view = useMemo(() => collectionView(snapshot, {
|
|
51
|
+
appName: app.name,
|
|
52
|
+
copy
|
|
53
|
+
}), [snapshot, app.name, copy]);
|
|
54
|
+
const [busy, setBusy] = useState(null);
|
|
55
|
+
const [error, setError] = useState(null);
|
|
56
|
+
const [signOutPrompt, setSignOutPrompt] = useState(null);
|
|
57
|
+
const running = useRef(null);
|
|
58
|
+
const latest = useRef({
|
|
59
|
+
options,
|
|
60
|
+
view
|
|
61
|
+
});
|
|
62
|
+
latest.current = {
|
|
63
|
+
options,
|
|
64
|
+
view
|
|
65
|
+
};
|
|
66
|
+
const actions = useMemo(() => {
|
|
67
|
+
/**
|
|
68
|
+
* Calls the SDK first, synchronously, then records state: Connect windows
|
|
69
|
+
* are reserved inside `call`, before anything here awaits.
|
|
70
|
+
*/
|
|
71
|
+
const run = (name, call, again = false) => {
|
|
72
|
+
if (running.current && !again) return Promise.resolve();
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
let pending;
|
|
75
|
+
try {
|
|
76
|
+
pending = call(controller.signal);
|
|
77
|
+
} catch (cause) {
|
|
78
|
+
pending = Promise.reject(cause);
|
|
79
|
+
}
|
|
80
|
+
const kind = latest.current.view.kind;
|
|
81
|
+
running.current = {
|
|
82
|
+
name,
|
|
83
|
+
controller
|
|
84
|
+
};
|
|
85
|
+
setBusy(name);
|
|
86
|
+
setError(null);
|
|
87
|
+
return pending.then(() => undefined, cause => {
|
|
88
|
+
const problem = describeError(cause);
|
|
89
|
+
if (problem) console.info("[mdbase collections]", problem.code, problem.developerMessage ?? "");
|
|
90
|
+
if (name === "sign_out" && problem?.key === "sign_out_pending_writes") setSignOutPrompt(problem);else if (!controller.signal.aborted) {
|
|
91
|
+
const notice = actionNotice(problem);
|
|
92
|
+
setError(notice ? {
|
|
93
|
+
kind,
|
|
94
|
+
notice
|
|
95
|
+
} : null);
|
|
96
|
+
}
|
|
97
|
+
}).finally(() => {
|
|
98
|
+
if (running.current?.controller !== controller) return;
|
|
99
|
+
running.current = null;
|
|
100
|
+
setBusy(null);
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
/** Ask the app first when leaving the open collection; continue in the same task when it agrees. */
|
|
104
|
+
const leave = (intent, go) => {
|
|
105
|
+
const {
|
|
106
|
+
options: current,
|
|
107
|
+
view: now
|
|
108
|
+
} = latest.current;
|
|
109
|
+
const open = now.current !== null || appOpenItem(current.sections) !== null;
|
|
110
|
+
const answer = open && current.onBeforeLeave ? current.onBeforeLeave(intent) : true;
|
|
111
|
+
if (answer === true) go();else if (answer !== false) void answer.then(ok => {
|
|
112
|
+
if (ok) go();
|
|
113
|
+
}, () => {});
|
|
114
|
+
};
|
|
115
|
+
const addCollection = () => leave("add", () => {
|
|
116
|
+
void run("add", signal => mdbase.addCollection({
|
|
117
|
+
signal
|
|
118
|
+
}));
|
|
119
|
+
});
|
|
120
|
+
const actions = {
|
|
121
|
+
signIn: () => {
|
|
122
|
+
void run("sign_in", signal => mdbase.signIn({
|
|
123
|
+
signal
|
|
124
|
+
}));
|
|
125
|
+
},
|
|
126
|
+
addCollection,
|
|
127
|
+
addPrivateCollection: addCollection,
|
|
128
|
+
approve: id => {
|
|
129
|
+
void run("approve", signal => mdbase.approve(id ?? undefined, {
|
|
130
|
+
signal
|
|
131
|
+
}));
|
|
132
|
+
},
|
|
133
|
+
select: id => {
|
|
134
|
+
const app = appOpenItem(latest.current.options.sections);
|
|
135
|
+
if (!app && latest.current.view.current?.id === id) return;
|
|
136
|
+
leave("switch", () => {
|
|
137
|
+
app?.section.onClose?.(app.item);
|
|
138
|
+
void run("select", signal => mdbase.select(id, {
|
|
139
|
+
signal
|
|
140
|
+
}));
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
selectItem: (section, item) => {
|
|
144
|
+
if (item.current || item.disabled) return;
|
|
145
|
+
leave("switch", () => {
|
|
146
|
+
const app = appOpenItem(latest.current.options.sections);
|
|
147
|
+
if (app && app.item.id !== item.id) app.section.onClose?.(app.item);
|
|
148
|
+
section.onSelect(item);
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
chooseAnother: () => leave("choose_another", () => {
|
|
152
|
+
const app = appOpenItem(latest.current.options.sections);
|
|
153
|
+
app?.section.onClose?.(app.item);
|
|
154
|
+
if (!app || latest.current.view.current) void run("choose_another", signal => mdbase.chooseAnother({
|
|
155
|
+
signal
|
|
156
|
+
}));
|
|
157
|
+
}),
|
|
158
|
+
reopen: () => {
|
|
159
|
+
const now = latest.current.view;
|
|
160
|
+
if (now.kind !== "authorizing") return;
|
|
161
|
+
const call = now.purpose === "sign_in" ? signal => mdbase.signIn({
|
|
162
|
+
signal
|
|
163
|
+
}) : now.purpose === "add" ? signal => mdbase.addCollection({
|
|
164
|
+
signal
|
|
165
|
+
}) : signal => mdbase.approve(now.collectionId ?? undefined, {
|
|
166
|
+
signal
|
|
167
|
+
});
|
|
168
|
+
void run(now.purpose === "sign_in" ? "sign_in" : now.purpose === "add" ? "add" : "approve", call, true);
|
|
169
|
+
},
|
|
170
|
+
cancel: () => {
|
|
171
|
+
const current = running.current;
|
|
172
|
+
if (current && popupActions.has(current.name)) current.controller.abort();
|
|
173
|
+
},
|
|
174
|
+
assess: () => {
|
|
175
|
+
void run("assess", signal => mdbase.assess({
|
|
176
|
+
signal
|
|
177
|
+
}));
|
|
178
|
+
},
|
|
179
|
+
start: () => {
|
|
180
|
+
void run("start", signal => mdbase.start({
|
|
181
|
+
signal
|
|
182
|
+
}));
|
|
183
|
+
},
|
|
184
|
+
signOut: () => leave("sign_out", () => {
|
|
185
|
+
void run("sign_out", signal => mdbase.signOut({
|
|
186
|
+
signal
|
|
187
|
+
}));
|
|
188
|
+
}),
|
|
189
|
+
confirmSignOut: () => {
|
|
190
|
+
setSignOutPrompt(null);
|
|
191
|
+
void run("sign_out", signal => mdbase.signOut({
|
|
192
|
+
signal,
|
|
193
|
+
discard: true
|
|
194
|
+
}), true);
|
|
195
|
+
},
|
|
196
|
+
dismissSignOut: () => setSignOutPrompt(null),
|
|
197
|
+
perform: (control, onSetUp) => {
|
|
198
|
+
switch (control.kind) {
|
|
199
|
+
case "sign_in":
|
|
200
|
+
return actions.signIn();
|
|
201
|
+
case "approve":
|
|
202
|
+
return actions.approve(control.collectionId);
|
|
203
|
+
case "choose_another":
|
|
204
|
+
return actions.chooseAnother();
|
|
205
|
+
case "set_up":
|
|
206
|
+
return onSetUp?.();
|
|
207
|
+
case "assess":
|
|
208
|
+
return actions.assess();
|
|
209
|
+
case "start":
|
|
210
|
+
return actions.start();
|
|
211
|
+
case "reload":
|
|
212
|
+
return globalThis.location?.reload();
|
|
213
|
+
case "link":
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
track: (name, call) => run(name, call, true)
|
|
218
|
+
};
|
|
219
|
+
return actions;
|
|
220
|
+
}, [mdbase]);
|
|
221
|
+
const say = useMemo(() => (key, values = {}) => fill(copy[key], {
|
|
222
|
+
app: app.name,
|
|
223
|
+
...values
|
|
224
|
+
}), [copy, app.name]);
|
|
225
|
+
return {
|
|
226
|
+
view,
|
|
227
|
+
copy,
|
|
228
|
+
say,
|
|
229
|
+
options,
|
|
230
|
+
busy,
|
|
231
|
+
signOutPrompt,
|
|
232
|
+
actions,
|
|
233
|
+
appOpen: appOpenItem(options.sections),
|
|
234
|
+
error: error && error.kind === view.kind ? error.notice : null
|
|
235
|
+
};
|
|
236
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@mdbase-dev/ui/collections`: the shared collection screens. Import
|
|
3
|
+
* `@mdbase-dev/ui/collections.css` once. The SDK (`createMdbase`) is a peer.
|
|
4
|
+
*/
|
|
5
|
+
export { CollectionGate, CollectionPanel, CollectionProblem } from "./collections/CollectionGate.js";
|
|
6
|
+
export type { AppCollectionContext, CollectionExtraActions, CollectionGateOwnProps, CollectionGateProps, CollectionPanelProps, CollectionProblemProps } from "./collections/CollectionGate.js";
|
|
7
|
+
export { CollectionSaveWarning, useCollectionSaveWarning } from "./collections/CollectionSaveWarning.js";
|
|
8
|
+
export { CollectionSwitcher } from "./collections/CollectionSwitcher.js";
|
|
9
|
+
export type { CollectionSwitcherProps } from "./collections/CollectionSwitcher.js";
|
|
10
|
+
export { SetupReview as CollectionSetupReview } from "./collections/SetupReview.js";
|
|
11
|
+
export { DeleteCollectionDialog, ForgetCollectionDialog } from "./collections/dialogs.js";
|
|
12
|
+
export { useAutoStart, useCollectionUi } from "./collections/use-collection-ui.js";
|
|
13
|
+
export type { CollectionActionName, CollectionActions, CollectionAppIdentity, CollectionSection, CollectionSectionItem, CollectionSectionItemAction, CollectionSectionItemActionContext, CollectionUi, CollectionUiOptions, DeleteCollectionOutcome, LeaveIntent, OpenSectionItem, } from "./collections/use-collection-ui.js";
|
|
14
|
+
export { collectionView, collectionRows, problemControl, accountLabel } from "./collections/model.js";
|
|
15
|
+
export type { CollectionNotice, CollectionRole, CollectionRow, CollectionView, CollectionViewKind, CollectionViewOptions, ProblemControl } from "./collections/model.js";
|
|
16
|
+
export { defaultCollectionCopy } from "./collections/copy.js";
|
|
17
|
+
export type { CollectionCopy, CollectionCopyKey } from "./collections/copy.js";
|
|
18
|
+
export { mountCollectionUi } from "./collections/mount.js";
|
|
19
|
+
export type { CollectionUiPart, MountCollectionUiOptions, MountedCollectionUi } from "./collections/mount.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@mdbase-dev/ui/collections`: the shared collection screens. Import
|
|
3
|
+
* `@mdbase-dev/ui/collections.css` once. The SDK (`createMdbase`) is a peer.
|
|
4
|
+
*/
|
|
5
|
+
export { CollectionGate, CollectionPanel, CollectionProblem } from "./collections/CollectionGate.js";
|
|
6
|
+
export { CollectionSaveWarning, useCollectionSaveWarning } from "./collections/CollectionSaveWarning.js";
|
|
7
|
+
export { CollectionSwitcher } from "./collections/CollectionSwitcher.js";
|
|
8
|
+
export { SetupReview as CollectionSetupReview } from "./collections/SetupReview.js";
|
|
9
|
+
export { DeleteCollectionDialog, ForgetCollectionDialog } from "./collections/dialogs.js";
|
|
10
|
+
export { useAutoStart, useCollectionUi } from "./collections/use-collection-ui.js";
|
|
11
|
+
export { collectionView, collectionRows, problemControl, accountLabel } from "./collections/model.js";
|
|
12
|
+
export { defaultCollectionCopy } from "./collections/copy.js";
|
|
13
|
+
export { mountCollectionUi } from "./collections/mount.js";
|
package/dist/feedback-data.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "./i18n.js";
|
|
1
2
|
export declare const FEEDBACK_MAX_MESSAGE_LENGTH = 5000;
|
|
2
3
|
export declare const FEEDBACK_MAX_SCREENSHOT_BYTES: number;
|
|
3
4
|
export declare const FEEDBACK_ERROR_CODES: readonly ["cancelled", "http_error", "invalid_response", "outcome_unknown", "partial_failure", "timeout", "network_error", "unknown_error", "save_failed", "source_open_failed", "preview_failed"];
|
|
@@ -44,22 +45,22 @@ export interface FeedbackSubmission {
|
|
|
44
45
|
}
|
|
45
46
|
export declare const feedbackTopics: {
|
|
46
47
|
problem: {
|
|
47
|
-
label: string;
|
|
48
|
-
prompt: string;
|
|
49
|
-
placeholder: string;
|
|
50
|
-
thanks: string;
|
|
48
|
+
readonly label: string;
|
|
49
|
+
readonly prompt: string;
|
|
50
|
+
readonly placeholder: string;
|
|
51
|
+
readonly thanks: string;
|
|
51
52
|
};
|
|
52
53
|
idea: {
|
|
53
|
-
label: string;
|
|
54
|
-
prompt: string;
|
|
55
|
-
placeholder: string;
|
|
56
|
-
thanks: string;
|
|
54
|
+
readonly label: string;
|
|
55
|
+
readonly prompt: string;
|
|
56
|
+
readonly placeholder: string;
|
|
57
|
+
readonly thanks: string;
|
|
57
58
|
};
|
|
58
59
|
appreciation: {
|
|
59
|
-
label: string;
|
|
60
|
-
prompt: string;
|
|
61
|
-
placeholder: string;
|
|
62
|
-
thanks: string;
|
|
60
|
+
readonly label: string;
|
|
61
|
+
readonly prompt: string;
|
|
62
|
+
readonly placeholder: string;
|
|
63
|
+
readonly thanks: string;
|
|
63
64
|
};
|
|
64
65
|
};
|
|
65
66
|
/** Each provider owns its bounded, short-lived error buffer; never accepts messages or request data. */
|