@mdbase-dev/ui 0.1.0-beta.126 → 0.1.0-beta.148
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 +168 -0
- package/css/collections.css +978 -0
- package/css/controls.css +33 -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/CollectionModeControl.d.ts +11 -0
- package/dist/CollectionModeControl.js +290 -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 +51 -0
- package/dist/collections/CollectionSwitcher.js +598 -0
- package/dist/collections/SetupReview.d.ts +9 -0
- package/dist/collections/SetupReview.js +216 -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 +19 -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 +56 -7
package/dist/SelectList.js
CHANGED
|
@@ -4,18 +4,63 @@ import { isOptionGroup, itemOffsets } from "./select-model.js";
|
|
|
4
4
|
* The listbox half of a select. Focus stays on the listbox, which names its active option with
|
|
5
5
|
* aria-activedescendant, so options take pointer input only; the keyboard goes to the list.
|
|
6
6
|
*/
|
|
7
|
-
export function SelectList({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
export function SelectList({
|
|
8
|
+
id,
|
|
9
|
+
listRef,
|
|
10
|
+
items,
|
|
11
|
+
selected,
|
|
12
|
+
active,
|
|
13
|
+
open,
|
|
14
|
+
label,
|
|
15
|
+
labelledBy,
|
|
16
|
+
onActivate,
|
|
17
|
+
onChoose,
|
|
18
|
+
onKeyDown
|
|
19
|
+
}) {
|
|
20
|
+
const offsets = itemOffsets(items);
|
|
21
|
+
const option = (value, index) => _jsx("div", {
|
|
22
|
+
id: `${id}-option-${String(index)}`,
|
|
23
|
+
"data-index": index,
|
|
24
|
+
"data-value": value.value,
|
|
25
|
+
role: "option",
|
|
26
|
+
"aria-selected": index === selected,
|
|
27
|
+
"aria-disabled": value.disabled ? true : undefined,
|
|
28
|
+
className: index === active ? "mdbase-select-option is-active" : "mdbase-select-option",
|
|
29
|
+
onPointerMove: () => {
|
|
30
|
+
if (!value.disabled && index !== active) {
|
|
31
|
+
onActivate(index);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
onClick: () => onChoose(index),
|
|
35
|
+
children: value.label
|
|
36
|
+
}, value.value);
|
|
37
|
+
return _jsx("div", {
|
|
38
|
+
ref: listRef,
|
|
39
|
+
id: `${id}-list`,
|
|
40
|
+
className: "mdbase-select-list",
|
|
41
|
+
popover: "manual",
|
|
42
|
+
role: "listbox",
|
|
43
|
+
tabIndex: -1,
|
|
44
|
+
"aria-label": label,
|
|
45
|
+
"aria-labelledby": labelledBy,
|
|
46
|
+
"aria-activedescendant": open && active >= 0 ? `${id}-option-${String(active)}` : undefined,
|
|
47
|
+
onKeyDown: onKeyDown,
|
|
48
|
+
onClick: event => {
|
|
49
|
+
event.stopPropagation();
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
},
|
|
52
|
+
onDoubleClick: event => event.stopPropagation(),
|
|
53
|
+
children: items.map((item, itemIndex) => {
|
|
54
|
+
const first = offsets[itemIndex] ?? 0;
|
|
55
|
+
return isOptionGroup(item) ? _jsxs("div", {
|
|
56
|
+
role: "group",
|
|
57
|
+
"aria-label": item.label,
|
|
58
|
+
children: [_jsx("div", {
|
|
59
|
+
className: "mdbase-select-group",
|
|
60
|
+
"aria-hidden": "true",
|
|
61
|
+
children: item.label
|
|
62
|
+
}), item.options.map((value, offset) => option(value, first + offset))]
|
|
63
|
+
}, `group:${item.label}`) : option(item, first);
|
|
64
|
+
})
|
|
65
|
+
});
|
|
21
66
|
}
|
package/dist/ThemeSelect.js
CHANGED
|
@@ -1,12 +1,63 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { i18n as _i18n } from "@lingui/core";
|
|
3
|
+
import { useLocaleRevision } from "./i18n.js";
|
|
2
4
|
import { Select } from "./Select.js";
|
|
3
5
|
import { themePreferences } from "./theme.js";
|
|
4
|
-
const themeLabels = {
|
|
5
|
-
|
|
6
|
+
const themeLabels = {
|
|
7
|
+
get system() {
|
|
8
|
+
return _i18n._(
|
|
9
|
+
/** i18n */
|
|
10
|
+
{
|
|
11
|
+
id: "XAe57G",
|
|
12
|
+
message: "System",
|
|
13
|
+
context: "Color theme"
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
get light() {
|
|
17
|
+
return _i18n._(
|
|
18
|
+
/** i18n */
|
|
19
|
+
{
|
|
20
|
+
id: "EbTBqo",
|
|
21
|
+
message: "Light",
|
|
22
|
+
context: "Color theme"
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
get dark() {
|
|
26
|
+
return _i18n._(
|
|
27
|
+
/** i18n */
|
|
28
|
+
{
|
|
29
|
+
id: "FPIkyE",
|
|
30
|
+
message: "Dark",
|
|
31
|
+
context: "Color theme"
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const themeOptions = () => themePreferences.map(value => ({
|
|
36
|
+
value,
|
|
37
|
+
label: themeLabels[value]
|
|
38
|
+
}));
|
|
6
39
|
/**
|
|
7
40
|
* The one control for choosing System, Light or Dark. The app owns the preference (with
|
|
8
41
|
* loadThemePreference and saveThemePreference) because commands and menus may change it too.
|
|
9
42
|
*/
|
|
10
|
-
export function ThemeSelect({
|
|
11
|
-
|
|
43
|
+
export function ThemeSelect({
|
|
44
|
+
value,
|
|
45
|
+
onChange,
|
|
46
|
+
className,
|
|
47
|
+
label = _i18n._(
|
|
48
|
+
/** i18n */
|
|
49
|
+
{
|
|
50
|
+
id: "IspNTR",
|
|
51
|
+
message: "Color theme",
|
|
52
|
+
context: "Color theme"
|
|
53
|
+
})
|
|
54
|
+
}) {
|
|
55
|
+
useLocaleRevision();
|
|
56
|
+
return _jsx(Select, {
|
|
57
|
+
"aria-label": label,
|
|
58
|
+
className: className,
|
|
59
|
+
value: value,
|
|
60
|
+
options: themeOptions(),
|
|
61
|
+
onChange: onChange
|
|
62
|
+
});
|
|
12
63
|
}
|
package/dist/apps.d.ts
CHANGED
package/dist/apps.js
CHANGED
|
@@ -1,32 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+
import { i18n as _i18n } from "@lingui/core";
|
|
2
|
+
import "./i18n.js";
|
|
3
|
+
export const mdbaseApps = [{
|
|
4
|
+
id: "editor",
|
|
5
|
+
name: "Editor",
|
|
6
|
+
get description() {
|
|
7
|
+
return _i18n._(
|
|
8
|
+
/** i18n */
|
|
2
9
|
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
id: "IseQAg",
|
|
11
|
+
message: "Browse and edit records"
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
url: "https://editor.mdbase.dev/"
|
|
15
|
+
}, {
|
|
16
|
+
id: "reader",
|
|
17
|
+
name: "Reader",
|
|
18
|
+
get description() {
|
|
19
|
+
return _i18n._(
|
|
20
|
+
/** i18n */
|
|
8
21
|
{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
22
|
+
id: "kHiGeJ",
|
|
23
|
+
message: "Read and annotate sources"
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
url: "https://reader.mdbase.dev/"
|
|
27
|
+
}, {
|
|
28
|
+
id: "writer",
|
|
29
|
+
name: "Writer",
|
|
30
|
+
get description() {
|
|
31
|
+
return _i18n._(
|
|
32
|
+
/** i18n */
|
|
14
33
|
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
];
|
|
34
|
+
id: "wv1f8v",
|
|
35
|
+
message: "Write manuscripts that cite your sources"
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
url: "https://writer.mdbase.dev/"
|
|
39
|
+
}];
|
|
21
40
|
/**
|
|
22
41
|
* Replaces app URLs for a lab or local build, for example from
|
|
23
42
|
* `import.meta.env.VITE_MDBASE_WRITER_URL`. Unset entries keep production.
|
|
24
43
|
*/
|
|
25
44
|
export function withAppUrls(urls, apps = mdbaseApps) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
45
|
+
return apps.map(app => {
|
|
46
|
+
const url = urls[app.id];
|
|
47
|
+
return url ? {
|
|
48
|
+
...app,
|
|
49
|
+
url
|
|
50
|
+
} : app;
|
|
51
|
+
});
|
|
30
52
|
}
|
|
31
53
|
/**
|
|
32
54
|
* Parameters every mdbase app reads the same way: `collection` is the Connect SDK's
|
|
@@ -36,12 +58,11 @@ export function withAppUrls(urls, apps = mdbaseApps) {
|
|
|
36
58
|
const sharedParameters = ["collection", "server"];
|
|
37
59
|
/** A link that opens the current page's collection in another app. */
|
|
38
60
|
export function mdbaseAppHref(appUrl, currentHref) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return target.href;
|
|
61
|
+
const target = new URL(appUrl);
|
|
62
|
+
const current = new URL(currentHref);
|
|
63
|
+
for (const key of sharedParameters) {
|
|
64
|
+
const value = current.searchParams.get(key);
|
|
65
|
+
if (value) target.searchParams.set(key, value);
|
|
66
|
+
}
|
|
67
|
+
return target.href;
|
|
47
68
|
}
|
package/dist/brand.js
CHANGED
|
@@ -1,63 +1,134 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useId, useRef, useState } from "react";
|
|
3
3
|
/** Indeterminate waits. Each repeats until the motion is removed. */
|
|
4
|
-
export const mdbaseMarkLoops = [
|
|
5
|
-
"orbit",
|
|
6
|
-
"scan",
|
|
7
|
-
"bounce",
|
|
8
|
-
"stream",
|
|
9
|
-
"sort",
|
|
10
|
-
"hop"
|
|
11
|
-
];
|
|
4
|
+
export const mdbaseMarkLoops = ["orbit", "scan", "bounce", "stream", "sort", "hop"];
|
|
12
5
|
/** Played once when the mark appears; the mark then rests. */
|
|
13
|
-
export const mdbaseMarkEntrances = [
|
|
14
|
-
"keys-first",
|
|
15
|
-
"drop",
|
|
16
|
-
"assemble"
|
|
17
|
-
];
|
|
6
|
+
export const mdbaseMarkEntrances = ["keys-first", "drop", "assemble"];
|
|
18
7
|
export const mdbaseMarkMotions = [...mdbaseMarkLoops, ...mdbaseMarkEntrances];
|
|
19
8
|
/** Long enough for each entrance in `motion.css` to finish. */
|
|
20
9
|
const ENTRANCE_MS = 1300;
|
|
21
10
|
export function mdbaseMarkMotionClass(motion) {
|
|
22
|
-
|
|
11
|
+
return motion ? ` mdbase-motion-${motion}` : "";
|
|
23
12
|
}
|
|
24
13
|
function isEntrance(motion) {
|
|
25
|
-
|
|
14
|
+
return mdbaseMarkEntrances.includes(motion ?? "");
|
|
26
15
|
}
|
|
27
16
|
export const MDBASE_MARK_VIEW_BOX = "18 18 84 84";
|
|
28
|
-
export const mdbaseMarkInkRects = [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
17
|
+
export const mdbaseMarkInkRects = [{
|
|
18
|
+
x: 22,
|
|
19
|
+
y: 22,
|
|
20
|
+
width: 20,
|
|
21
|
+
height: 10
|
|
22
|
+
}, {
|
|
23
|
+
x: 50,
|
|
24
|
+
y: 22,
|
|
25
|
+
width: 20,
|
|
26
|
+
height: 10
|
|
27
|
+
}, {
|
|
28
|
+
x: 78,
|
|
29
|
+
y: 22,
|
|
30
|
+
width: 20,
|
|
31
|
+
height: 10
|
|
32
|
+
}, {
|
|
33
|
+
x: 22,
|
|
34
|
+
y: 44,
|
|
35
|
+
width: 12,
|
|
36
|
+
height: 10
|
|
37
|
+
}, {
|
|
38
|
+
x: 22,
|
|
39
|
+
y: 66,
|
|
40
|
+
width: 28,
|
|
41
|
+
height: 10
|
|
42
|
+
}, {
|
|
43
|
+
x: 58,
|
|
44
|
+
y: 66,
|
|
45
|
+
width: 40,
|
|
46
|
+
height: 10
|
|
47
|
+
}, {
|
|
48
|
+
x: 22,
|
|
49
|
+
y: 88,
|
|
50
|
+
width: 20,
|
|
51
|
+
height: 10
|
|
52
|
+
}, {
|
|
53
|
+
x: 50,
|
|
54
|
+
y: 88,
|
|
55
|
+
width: 20,
|
|
56
|
+
height: 10
|
|
57
|
+
}, {
|
|
58
|
+
x: 78,
|
|
59
|
+
y: 88,
|
|
60
|
+
width: 20,
|
|
61
|
+
height: 10
|
|
62
|
+
}];
|
|
39
63
|
export const mdbaseMarkAccentRect = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
x: 42,
|
|
65
|
+
y: 44,
|
|
66
|
+
width: 56,
|
|
67
|
+
height: 10
|
|
44
68
|
};
|
|
45
69
|
const lineYs = [22, 44, 66, 88];
|
|
46
70
|
const orbitXs = [-34, -6, 22, 50, 78, 106];
|
|
47
71
|
function classes(...names) {
|
|
48
|
-
|
|
72
|
+
return names.filter(Boolean).join(" ");
|
|
49
73
|
}
|
|
50
74
|
/** How much of each line is filled when `progress` of the whole is done, in reading order. */
|
|
51
75
|
export function mdbaseMarkLineFill(progress) {
|
|
52
|
-
|
|
53
|
-
|
|
76
|
+
const clamped = Math.min(1, Math.max(0, progress));
|
|
77
|
+
return lineYs.map((_, line) => Math.min(1, Math.max(0, clamped * lineYs.length - line)));
|
|
54
78
|
}
|
|
55
|
-
function Segment({
|
|
56
|
-
|
|
79
|
+
function Segment({
|
|
80
|
+
rect,
|
|
81
|
+
index,
|
|
82
|
+
accent = false
|
|
83
|
+
}) {
|
|
84
|
+
return _jsx("rect", {
|
|
85
|
+
className: `mdbase-mark-segment mdbase-mark-segment-${index} ${accent ? "mdbase-mark-accent" : "mdbase-mark-ink"}`,
|
|
86
|
+
...rect
|
|
87
|
+
});
|
|
57
88
|
}
|
|
58
|
-
function Lines({
|
|
59
|
-
|
|
60
|
-
|
|
89
|
+
function Lines({
|
|
90
|
+
clipRows
|
|
91
|
+
}) {
|
|
92
|
+
const rows = _jsxs(_Fragment, {
|
|
93
|
+
children: [_jsxs("g", {
|
|
94
|
+
className: "mdbase-mark-row mdbase-mark-row-top",
|
|
95
|
+
children: [_jsx(Segment, {
|
|
96
|
+
rect: mdbaseMarkInkRects[3],
|
|
97
|
+
index: 4
|
|
98
|
+
}), _jsx(Segment, {
|
|
99
|
+
rect: mdbaseMarkAccentRect,
|
|
100
|
+
index: 5,
|
|
101
|
+
accent: true
|
|
102
|
+
})]
|
|
103
|
+
}), _jsxs("g", {
|
|
104
|
+
className: "mdbase-mark-row mdbase-mark-row-bottom",
|
|
105
|
+
children: [_jsx(Segment, {
|
|
106
|
+
rect: mdbaseMarkInkRects[4],
|
|
107
|
+
index: 6
|
|
108
|
+
}), _jsx(Segment, {
|
|
109
|
+
rect: mdbaseMarkInkRects[5],
|
|
110
|
+
index: 7
|
|
111
|
+
})]
|
|
112
|
+
})]
|
|
113
|
+
});
|
|
114
|
+
return _jsxs(_Fragment, {
|
|
115
|
+
children: [_jsx("g", {
|
|
116
|
+
className: "mdbase-mark-fence mdbase-mark-fence-top",
|
|
117
|
+
children: mdbaseMarkInkRects.slice(0, 3).map((rect, index) => _jsx(Segment, {
|
|
118
|
+
rect: rect,
|
|
119
|
+
index: index + 1
|
|
120
|
+
}, `${rect.x}-${rect.y}`))
|
|
121
|
+
}), clipRows ? _jsx("g", {
|
|
122
|
+
clipPath: `url(#${clipRows})`,
|
|
123
|
+
children: rows
|
|
124
|
+
}) : rows, _jsx("g", {
|
|
125
|
+
className: "mdbase-mark-fence mdbase-mark-fence-bottom",
|
|
126
|
+
children: mdbaseMarkInkRects.slice(6).map((rect, index) => _jsx(Segment, {
|
|
127
|
+
rect: rect,
|
|
128
|
+
index: index + 8
|
|
129
|
+
}, `${rect.x}-${rect.y}`))
|
|
130
|
+
})]
|
|
131
|
+
});
|
|
61
132
|
}
|
|
62
133
|
/**
|
|
63
134
|
* The Frontmatter mark. Without `app` it is the platform's own; with `app` it is
|
|
@@ -67,41 +138,153 @@ function Lines({ clipRows }) {
|
|
|
67
138
|
* whatever else is running, and `progress` (0 to 1) fills the lines in reading
|
|
68
139
|
* order over a faint copy of the mark. Animations live in `motion.css`.
|
|
69
140
|
*/
|
|
70
|
-
export function MdbaseMark({
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
141
|
+
export function MdbaseMark({
|
|
142
|
+
app,
|
|
143
|
+
motion,
|
|
144
|
+
signal,
|
|
145
|
+
progress,
|
|
146
|
+
className
|
|
147
|
+
}) {
|
|
148
|
+
const uid = useId().replaceAll(":", "");
|
|
149
|
+
// An entrance plays once per mark. Dropping its class afterwards stops it replaying when a signal
|
|
150
|
+
// remounts the lines, and remembering it stops a replay when a loop or progress hands back to it.
|
|
151
|
+
const [entering, setEntering] = useState(isEntrance(motion));
|
|
152
|
+
const played = useRef(undefined);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (!isEntrance(motion) || played.current === motion) return setEntering(false);
|
|
155
|
+
setEntering(true);
|
|
156
|
+
const timer = setTimeout(() => {
|
|
157
|
+
played.current = motion;
|
|
158
|
+
setEntering(false);
|
|
159
|
+
}, ENTRANCE_MS);
|
|
160
|
+
return () => clearTimeout(timer);
|
|
161
|
+
}, [motion]);
|
|
162
|
+
const showsProgress = typeof progress === "number" && Number.isFinite(progress);
|
|
163
|
+
const active = signal ? undefined : showsProgress ? undefined : isEntrance(motion) ? entering ? motion : undefined : motion;
|
|
164
|
+
const lines = _jsx(Lines, {
|
|
165
|
+
clipRows: active === "stream" ? `mdbase-rows-${uid}` : undefined
|
|
166
|
+
});
|
|
167
|
+
return _jsxs("svg", {
|
|
168
|
+
className: classes("mdbase-mark", app && "mdbase-app-mark", app && `is-${app}`, className, active && `mdbase-motion-${active}`, signal && `mdbase-signal-${signal.kind}`, showsProgress && "mdbase-mark-progress", !active && !signal && !showsProgress && "mdbase-mark-at-rest"),
|
|
169
|
+
viewBox: MDBASE_MARK_VIEW_BOX,
|
|
170
|
+
"aria-hidden": "true",
|
|
171
|
+
focusable: "false",
|
|
172
|
+
children: [active === "stream" && _jsx("defs", {
|
|
173
|
+
children: _jsx("clipPath", {
|
|
174
|
+
id: `mdbase-rows-${uid}`,
|
|
175
|
+
children: _jsx("rect", {
|
|
176
|
+
x: "22",
|
|
177
|
+
y: "40",
|
|
178
|
+
width: "76",
|
|
179
|
+
height: "40"
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
}), active === "orbit" && _jsxs("defs", {
|
|
183
|
+
children: [_jsx("clipPath", {
|
|
184
|
+
id: `mdbase-fence-top-${uid}`,
|
|
185
|
+
children: _jsx("rect", {
|
|
186
|
+
x: "22",
|
|
187
|
+
y: "22",
|
|
188
|
+
width: "76",
|
|
189
|
+
height: "10"
|
|
190
|
+
})
|
|
191
|
+
}), _jsx("clipPath", {
|
|
192
|
+
id: `mdbase-fence-bottom-${uid}`,
|
|
193
|
+
children: _jsx("rect", {
|
|
194
|
+
x: "22",
|
|
195
|
+
y: "88",
|
|
196
|
+
width: "76",
|
|
197
|
+
height: "10"
|
|
198
|
+
})
|
|
199
|
+
})]
|
|
200
|
+
}), showsProgress ? _jsxs(_Fragment, {
|
|
201
|
+
children: [_jsx("defs", {
|
|
202
|
+
children: _jsx("clipPath", {
|
|
203
|
+
id: `mdbase-progress-${uid}`,
|
|
204
|
+
children: mdbaseMarkLineFill(progress).map((fill, line) => _jsx("rect", {
|
|
205
|
+
className: "mdbase-mark-progress-fill",
|
|
206
|
+
x: "22",
|
|
207
|
+
y: lineYs[line] - 1,
|
|
208
|
+
height: "12",
|
|
209
|
+
style: {
|
|
210
|
+
width: `${(76 * fill).toFixed(2)}px`
|
|
211
|
+
}
|
|
212
|
+
}, line))
|
|
213
|
+
})
|
|
214
|
+
}), _jsx("g", {
|
|
215
|
+
className: "mdbase-mark-progress-ghost",
|
|
216
|
+
children: _jsx(Lines, {})
|
|
217
|
+
}), _jsx("g", {
|
|
218
|
+
clipPath: `url(#mdbase-progress-${uid})`,
|
|
219
|
+
children: _jsx(Lines, {})
|
|
220
|
+
})]
|
|
221
|
+
})
|
|
222
|
+
// Keyed by the signal so the same reaction can restart without replaying an entrance.
|
|
223
|
+
: _jsx("g", {
|
|
224
|
+
className: "mdbase-mark-lines",
|
|
225
|
+
children: lines
|
|
226
|
+
}, signal?.id ?? 0), active === "orbit" && _jsxs(_Fragment, {
|
|
227
|
+
children: [_jsx("g", {
|
|
228
|
+
clipPath: `url(#mdbase-fence-top-${uid})`,
|
|
229
|
+
children: _jsx("g", {
|
|
230
|
+
className: "mdbase-mark-track mdbase-mark-track-top",
|
|
231
|
+
children: orbitXs.map(x => _jsx("rect", {
|
|
232
|
+
x: x,
|
|
233
|
+
y: "22",
|
|
234
|
+
width: "20",
|
|
235
|
+
height: "10"
|
|
236
|
+
}, x))
|
|
237
|
+
})
|
|
238
|
+
}), _jsx("g", {
|
|
239
|
+
clipPath: `url(#mdbase-fence-bottom-${uid})`,
|
|
240
|
+
children: _jsx("g", {
|
|
241
|
+
className: "mdbase-mark-track mdbase-mark-track-bottom",
|
|
242
|
+
children: orbitXs.map(x => _jsx("rect", {
|
|
243
|
+
x: x,
|
|
244
|
+
y: "88",
|
|
245
|
+
width: "20",
|
|
246
|
+
height: "10"
|
|
247
|
+
}, x))
|
|
248
|
+
})
|
|
249
|
+
})]
|
|
250
|
+
})]
|
|
251
|
+
});
|
|
96
252
|
}
|
|
97
253
|
/** An app's mark. Kept for callers that only ever draw an app's still mark. */
|
|
98
|
-
export function MdbaseAppMark({
|
|
99
|
-
|
|
254
|
+
export function MdbaseAppMark({
|
|
255
|
+
app,
|
|
256
|
+
className
|
|
257
|
+
}) {
|
|
258
|
+
return _jsx(MdbaseMark, {
|
|
259
|
+
app: app,
|
|
260
|
+
className: className
|
|
261
|
+
});
|
|
100
262
|
}
|
|
101
263
|
/**
|
|
102
264
|
* `mdbase` followed by the product's quieter name. Editor carries the platform mark
|
|
103
265
|
* as the canonical app; Reader and Writer carry their app marks.
|
|
104
266
|
*/
|
|
105
|
-
export function Wordmark({
|
|
106
|
-
|
|
267
|
+
export function Wordmark({
|
|
268
|
+
app,
|
|
269
|
+
motion,
|
|
270
|
+
signal,
|
|
271
|
+
progress
|
|
272
|
+
}) {
|
|
273
|
+
return _jsxs("span", {
|
|
274
|
+
className: "wordmark",
|
|
275
|
+
children: [_jsx(MdbaseMark, {
|
|
276
|
+
app: app === "editor" ? undefined : app,
|
|
277
|
+
motion: motion,
|
|
278
|
+
signal: signal,
|
|
279
|
+
progress: progress,
|
|
280
|
+
className: "wordmark-mark"
|
|
281
|
+
}), _jsxs("span", {
|
|
282
|
+
className: "wordmark-label",
|
|
283
|
+
children: [_jsx("span", {
|
|
284
|
+
children: "mdbase"
|
|
285
|
+
}), _jsx("strong", {
|
|
286
|
+
children: app
|
|
287
|
+
})]
|
|
288
|
+
})]
|
|
289
|
+
});
|
|
107
290
|
}
|