@maple-kit/ui 0.1.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/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +39 -0
- package/dist/composer/actions.d.ts +15 -0
- package/dist/composer/actions.js +59 -0
- package/dist/composer/attachments.d.ts +33 -0
- package/dist/composer/attachments.js +166 -0
- package/dist/composer/badge.d.ts +13 -0
- package/dist/composer/badge.js +25 -0
- package/dist/composer/body.d.ts +13 -0
- package/dist/composer/body.js +119 -0
- package/dist/composer/composer.d.ts +23 -0
- package/dist/composer/composer.js +122 -0
- package/dist/composer/css.js +559 -0
- package/dist/composer/detail.d.ts +32 -0
- package/dist/composer/detail.js +102 -0
- package/dist/composer/emoji.d.ts +54 -0
- package/dist/composer/emoji.js +131 -0
- package/dist/composer/index.d.ts +15 -0
- package/dist/composer/index.js +15 -0
- package/dist/composer/inset.js +20 -0
- package/dist/composer/leave.d.ts +19 -0
- package/dist/composer/leave.js +34 -0
- package/dist/composer/peek.d.ts +21 -0
- package/dist/composer/peek.js +29 -0
- package/dist/composer/phrase.d.ts +27 -0
- package/dist/composer/phrase.js +30 -0
- package/dist/composer/picker-emoji.d.ts +34 -0
- package/dist/composer/picker-emoji.js +48 -0
- package/dist/composer/prompt.js +31 -0
- package/dist/composer/scope.d.ts +11 -0
- package/dist/composer/scope.js +16 -0
- package/dist/composer/target.d.ts +13 -0
- package/dist/composer/target.js +45 -0
- package/dist/context.d.ts +21 -0
- package/dist/context.js +16 -0
- package/dist/data.d.ts +52 -0
- package/dist/data.js +30 -0
- package/dist/icons/branch.d.ts +4 -0
- package/dist/icons/branch.js +8 -0
- package/dist/icons/cog.d.ts +4 -0
- package/dist/icons/cog.js +8 -0
- package/dist/icons/commit.d.ts +4 -0
- package/dist/icons/commit.js +5 -0
- package/dist/icons/crossfade.d.ts +15 -0
- package/dist/icons/crossfade.js +27 -0
- package/dist/icons/element.d.ts +4 -0
- package/dist/icons/element.js +5 -0
- package/dist/icons/icon.d.ts +24 -0
- package/dist/icons/icon.js +27 -0
- package/dist/icons/index.d.ts +13 -0
- package/dist/icons/index.js +13 -0
- package/dist/icons/noplace.d.ts +4 -0
- package/dist/icons/noplace.js +5 -0
- package/dist/icons/region.d.ts +4 -0
- package/dist/icons/region.js +8 -0
- package/dist/icons/smiley.d.ts +4 -0
- package/dist/icons/smiley.js +8 -0
- package/dist/icons/sparkle.d.ts +4 -0
- package/dist/icons/sparkle.js +8 -0
- package/dist/icons/target.d.ts +4 -0
- package/dist/icons/target.js +5 -0
- package/dist/icons/text.d.ts +4 -0
- package/dist/icons/text.js +5 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/island/account.d.ts +10 -0
- package/dist/island/account.js +52 -0
- package/dist/island/comments.d.ts +24 -0
- package/dist/island/comments.js +40 -0
- package/dist/island/content.d.ts +10 -0
- package/dist/island/content.js +26 -0
- package/dist/island/context.d.ts +58 -0
- package/dist/island/context.js +23 -0
- package/dist/island/css.d.ts +13 -0
- package/dist/island/css.js +1020 -0
- package/dist/island/drag.d.ts +10 -0
- package/dist/island/drag.js +77 -0
- package/dist/island/filters.d.ts +10 -0
- package/dist/island/filters.js +63 -0
- package/dist/island/header.d.ts +32 -0
- package/dist/island/header.js +47 -0
- package/dist/island/index.d.ts +18 -0
- package/dist/island/index.js +18 -0
- package/dist/island/island.d.ts +12 -0
- package/dist/island/island.js +111 -0
- package/dist/island/item.d.ts +12 -0
- package/dist/island/item.js +158 -0
- package/dist/island/language.d.ts +55 -0
- package/dist/island/language.js +125 -0
- package/dist/island/leaf.js +17 -0
- package/dist/island/list.d.ts +12 -0
- package/dist/island/list.js +31 -0
- package/dist/island/new-comment.d.ts +18 -0
- package/dist/island/new-comment.js +56 -0
- package/dist/island/settings.d.ts +10 -0
- package/dist/island/settings.js +134 -0
- package/dist/island/stagger.d.ts +12 -0
- package/dist/island/stagger.js +4 -0
- package/dist/island/time.d.ts +17 -0
- package/dist/island/time.js +29 -0
- package/dist/island/trigger.d.ts +10 -0
- package/dist/island/trigger.js +39 -0
- package/dist/language.d.ts +45 -0
- package/dist/language.js +66 -0
- package/dist/maple.d.ts +25 -0
- package/dist/maple.js +65 -0
- package/dist/marks/avatar.d.ts +16 -0
- package/dist/marks/avatar.js +36 -0
- package/dist/marks/css.d.ts +12 -0
- package/dist/marks/css.js +371 -0
- package/dist/marks/frame.d.ts +25 -0
- package/dist/marks/frame.js +53 -0
- package/dist/marks/geometry.d.ts +55 -0
- package/dist/marks/geometry.js +61 -0
- package/dist/marks/index.d.ts +14 -0
- package/dist/marks/index.js +14 -0
- package/dist/marks/label.d.ts +23 -0
- package/dist/marks/label.js +31 -0
- package/dist/marks/layer.d.ts +16 -0
- package/dist/marks/layer.js +194 -0
- package/dist/marks/leaf.d.ts +18 -0
- package/dist/marks/leaf.js +7 -0
- package/dist/marks/mark.d.ts +28 -0
- package/dist/marks/mark.js +43 -0
- package/dist/marks/nudge.d.ts +50 -0
- package/dist/marks/nudge.js +76 -0
- package/dist/marks/paint.d.ts +11 -0
- package/dist/marks/paint.js +19 -0
- package/dist/marks/placement.d.ts +24 -0
- package/dist/marks/placement.js +28 -0
- package/dist/marks/ring.d.ts +28 -0
- package/dist/marks/ring.js +85 -0
- package/dist/marks/shape.d.ts +21 -0
- package/dist/marks/shape.js +51 -0
- package/dist/notice/css.d.ts +11 -0
- package/dist/notice/css.js +74 -0
- package/dist/notice/index.d.ts +4 -0
- package/dist/notice/index.js +4 -0
- package/dist/notice/language.d.ts +15 -0
- package/dist/notice/language.js +14 -0
- package/dist/notice/notice.d.ts +14 -0
- package/dist/notice/notice.js +49 -0
- package/dist/part.d.ts +9 -0
- package/dist/part.js +11 -0
- package/dist/picker/css.d.ts +13 -0
- package/dist/picker/css.js +141 -0
- package/dist/picker/index.d.ts +6 -0
- package/dist/picker/index.js +6 -0
- package/dist/picker/language.d.ts +14 -0
- package/dist/picker/language.js +17 -0
- package/dist/picker/picker.d.ts +18 -0
- package/dist/picker/picker.js +164 -0
- package/dist/picker/session.d.ts +16 -0
- package/dist/picker/session.js +35 -0
- package/dist/picker/target.d.ts +23 -0
- package/dist/picker/target.js +37 -0
- package/dist/root.d.ts +42 -0
- package/dist/root.js +75 -0
- package/dist/shots.js +32 -0
- package/dist/slot.d.ts +28 -0
- package/dist/slot.js +52 -0
- package/dist/slots.d.ts +24 -0
- package/dist/slots.js +75 -0
- package/dist/stylesheet.d.ts +15 -0
- package/dist/stylesheet.js +188 -0
- package/dist/theme.d.ts +20 -0
- package/dist/theme.js +13 -0
- package/dist/tip.d.ts +40 -0
- package/dist/tip.js +82 -0
- package/dist/tokens.d.ts +28 -0
- package/dist/tokens.js +180 -0
- package/package.json +56 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AvatarProps, MapleAvatar, initialsOf } from "./avatar.js";
|
|
2
|
+
import { marksCss } from "./css.js";
|
|
3
|
+
import { Paint, startFrameLoop, useFrameLoop, viewportHeight } from "./frame.js";
|
|
4
|
+
import { Box, COLLISION_GAP_PX, COLLISION_MAX_TRIES, COLLISION_STEP_PX, MARK_HIT_PX, MARK_OFFSET_PX, MARK_SIZE_PX, Waterline, culled, markSpot, placeMark, ringBox, runBox, waterline } from "./geometry.js";
|
|
5
|
+
import { NOTHING_NAMED, RingLabel, kindPhrase, markLabel, markTitle, ringLabel } from "./label.js";
|
|
6
|
+
import { MapleMarkLayer, MarkLayerProps } from "./layer.js";
|
|
7
|
+
import { LEAF_OUTLINE, LEAF_ROTATION, LEAF_SOLID, LEAF_VIEW_BOX } from "./leaf.js";
|
|
8
|
+
import { MapleMark, MarkProps } from "./mark.js";
|
|
9
|
+
import { NUDGE_LIMIT_PX, NUDGE_THRESHOLD_PX, Nudge, NudgeHandlers, NudgePointer, Nudges, clampNudge, dragged, useNudges } from "./nudge.js";
|
|
10
|
+
import { MOVING_ATTRIBUTE, OFF_ATTRIBUTE, flag, place } from "./paint.js";
|
|
11
|
+
import { Placement, addresses, placements } from "./placement.js";
|
|
12
|
+
import { BELOW_ATTRIBUTE, MapleTargetRing, RingState, TargetRingProps } from "./ring.js";
|
|
13
|
+
import { HALF, LeafProps, MapleLeaf, nextClipId } from "./shape.js";
|
|
14
|
+
export { MapleAvatar as Avatar, type AvatarProps, BELOW_ATTRIBUTE, type Box, COLLISION_GAP_PX, COLLISION_MAX_TRIES, COLLISION_STEP_PX, HALF, LEAF_OUTLINE, LEAF_ROTATION, LEAF_SOLID, LEAF_VIEW_BOX, MapleLeaf as Leaf, type LeafProps, MARK_HIT_PX, MARK_OFFSET_PX, MARK_SIZE_PX, MOVING_ATTRIBUTE, MapleAvatar, MapleLeaf, MapleMark, MapleMarkLayer, MapleTargetRing, MapleMark as Mark, MapleMarkLayer as MarkLayer, type MarkLayerProps, type MarkProps, NOTHING_NAMED, NUDGE_LIMIT_PX, NUDGE_THRESHOLD_PX, type Nudge, type NudgeHandlers, type NudgePointer, type Nudges, OFF_ATTRIBUTE, type Paint, type Placement, type RingLabel, type RingState, MapleTargetRing as TargetRing, type TargetRingProps, type Waterline, addresses, clampNudge, culled, dragged, flag, initialsOf, kindPhrase, markLabel, markSpot, markTitle, marksCss, nextClipId, place, placeMark, placements, ringBox, ringLabel, runBox, startFrameLoop, useFrameLoop, useNudges, viewportHeight, waterline };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { marksCss } from "./css.js";
|
|
2
|
+
import { LEAF_OUTLINE, LEAF_ROTATION, LEAF_SOLID, LEAF_VIEW_BOX } from "./leaf.js";
|
|
3
|
+
import { COLLISION_GAP_PX, COLLISION_MAX_TRIES, COLLISION_STEP_PX, MARK_HIT_PX, MARK_OFFSET_PX, MARK_SIZE_PX, culled, markSpot, placeMark, ringBox, runBox, waterline } from "./geometry.js";
|
|
4
|
+
import { HALF, MapleLeaf, nextClipId } from "./shape.js";
|
|
5
|
+
import { MapleAvatar, initialsOf } from "./avatar.js";
|
|
6
|
+
import { startFrameLoop, useFrameLoop, viewportHeight } from "./frame.js";
|
|
7
|
+
import { NOTHING_NAMED, kindPhrase, markLabel, markTitle, ringLabel } from "./label.js";
|
|
8
|
+
import { MapleMark } from "./mark.js";
|
|
9
|
+
import { NUDGE_LIMIT_PX, NUDGE_THRESHOLD_PX, clampNudge, dragged, useNudges } from "./nudge.js";
|
|
10
|
+
import { MOVING_ATTRIBUTE, OFF_ATTRIBUTE, flag, place } from "./paint.js";
|
|
11
|
+
import { addresses, placements } from "./placement.js";
|
|
12
|
+
import { BELOW_ATTRIBUTE, MapleTargetRing } from "./ring.js";
|
|
13
|
+
import { MapleMarkLayer } from "./layer.js";
|
|
14
|
+
export { MapleAvatar as Avatar, BELOW_ATTRIBUTE, COLLISION_GAP_PX, COLLISION_MAX_TRIES, COLLISION_STEP_PX, HALF, LEAF_OUTLINE, LEAF_ROTATION, LEAF_SOLID, LEAF_VIEW_BOX, MapleLeaf as Leaf, MARK_HIT_PX, MARK_OFFSET_PX, MARK_SIZE_PX, MOVING_ATTRIBUTE, MapleAvatar, MapleLeaf, MapleMark, MapleMarkLayer, MapleTargetRing, MapleMark as Mark, MapleMarkLayer as MarkLayer, NOTHING_NAMED, NUDGE_LIMIT_PX, NUDGE_THRESHOLD_PX, OFF_ATTRIBUTE, MapleTargetRing as TargetRing, addresses, clampNudge, culled, dragged, flag, initialsOf, kindPhrase, markLabel, markSpot, markTitle, marksCss, nextClipId, place, placeMark, placements, ringBox, ringLabel, runBox, startFrameLoop, useFrameLoop, useNudges, viewportHeight, waterline };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PickKind } from "@maple-kit/core/client";
|
|
2
|
+
import { Anchor } from "@maple-kit/core/anchor";
|
|
3
|
+
import { CommentStatus } from "@maple-kit/core";
|
|
4
|
+
//#region src/marks/label.d.ts
|
|
5
|
+
/** What a comment is on, when nothing on the page names it. */
|
|
6
|
+
export declare const NOTHING_NAMED = "this page";
|
|
7
|
+
/** Everything the ring's label is built from. Each field may be missing. */
|
|
8
|
+
export interface RingLabel {
|
|
9
|
+
readonly kind?: PickKind;
|
|
10
|
+
readonly element?: Element | null;
|
|
11
|
+
readonly anchor?: Anchor;
|
|
12
|
+
/** What the composer already named it, which wins over re-reading the page. */
|
|
13
|
+
readonly named?: string;
|
|
14
|
+
}
|
|
15
|
+
/** The phrase for one kind of target: an element is simply its own name. */
|
|
16
|
+
export declare function kindPhrase(kind: PickKind | undefined, human: string | undefined): string;
|
|
17
|
+
/** The ring's words: the application's name for the thing, in a phrase. */
|
|
18
|
+
export declare function ringLabel(label: RingLabel): string;
|
|
19
|
+
/** The mark's tooltip: who, where in its life, and what it is on. */
|
|
20
|
+
export declare function markTitle(author: string | undefined, status: CommentStatus, on?: string): string;
|
|
21
|
+
/** The mark's accessible name. The address comes first, because it is the address. */
|
|
22
|
+
export declare function markLabel(address: number, author: string | undefined, status: CommentStatus): string;
|
|
23
|
+
//#endregion
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { STATUS_LABELS } from "../language.js";
|
|
2
|
+
import { labelFor } from "@maple-kit/core/anchor";
|
|
3
|
+
//#region src/marks/label.ts
|
|
4
|
+
const NOTHING_NAMED = "this page";
|
|
5
|
+
function kindPhrase(kind, human) {
|
|
6
|
+
if (!human) return NOTHING_NAMED;
|
|
7
|
+
if (kind === "text") return `a passage in ${human}`;
|
|
8
|
+
return kind === "region" ? `an area of ${human}` : human;
|
|
9
|
+
}
|
|
10
|
+
function ringLabel(label) {
|
|
11
|
+
const human = label.named ?? labelFor({
|
|
12
|
+
...label.element === void 0 ? {} : { element: label.element },
|
|
13
|
+
...label.anchor === void 0 ? {} : { anchor: label.anchor }
|
|
14
|
+
});
|
|
15
|
+
return kindPhrase(label.kind, human);
|
|
16
|
+
}
|
|
17
|
+
function joined(parts) {
|
|
18
|
+
return parts.filter(Boolean).join(" · ");
|
|
19
|
+
}
|
|
20
|
+
function markTitle(author, status, on) {
|
|
21
|
+
return joined([
|
|
22
|
+
author,
|
|
23
|
+
STATUS_LABELS[status],
|
|
24
|
+
on
|
|
25
|
+
]);
|
|
26
|
+
}
|
|
27
|
+
function markLabel(address, author, status) {
|
|
28
|
+
return `Comment ${address}${author ? ` by ${author}` : ""}, ${STATUS_LABELS[status]}`;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { NOTHING_NAMED, kindPhrase, markLabel, markTitle, ringLabel };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Comment } from "@maple-kit/core";
|
|
2
|
+
//#region src/marks/layer.d.ts
|
|
3
|
+
/** What the layer draws. Both lists default to the controller's own. */
|
|
4
|
+
export interface MarkLayerProps {
|
|
5
|
+
/** Everything on the branch: what the addresses are counted from. */
|
|
6
|
+
readonly comments?: readonly Comment[];
|
|
7
|
+
/** The ones to draw. Defaults to what the current filter shows. */
|
|
8
|
+
readonly visible?: readonly Comment[];
|
|
9
|
+
readonly selectedId?: string;
|
|
10
|
+
/** What a click does. Defaults to opening the comment, which is the point. */
|
|
11
|
+
readonly onSelect?: (comment: Comment) => void;
|
|
12
|
+
readonly className?: string;
|
|
13
|
+
}
|
|
14
|
+
/** The marks, and the one ring they share. */
|
|
15
|
+
export declare const MapleMarkLayer: import("react").ForwardRefExoticComponent<MarkLayerProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
16
|
+
//#endregion
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { useMapleUi } from "../context.js";
|
|
2
|
+
import { culled, markSpot, placeMark } from "./geometry.js";
|
|
3
|
+
import { useFrameLoop, viewportHeight } from "./frame.js";
|
|
4
|
+
import { ringLabel } from "./label.js";
|
|
5
|
+
import { MapleMark } from "./mark.js";
|
|
6
|
+
import { useNudges } from "./nudge.js";
|
|
7
|
+
import { OFF_ATTRIBUTE, flag, place } from "./paint.js";
|
|
8
|
+
import { addresses, placements } from "./placement.js";
|
|
9
|
+
import { MapleTargetRing } from "./ring.js";
|
|
10
|
+
import { createElement, forwardRef, useCallback, useEffect, useMemo, useRef } from "react";
|
|
11
|
+
import { useMaple, useMapleClient } from "@maple-kit/react";
|
|
12
|
+
import { kindOf, regionBox, resolveAnchor, sourceFor } from "@maple-kit/core/anchor";
|
|
13
|
+
//#region src/marks/layer.ts
|
|
14
|
+
const PART = "Maple.MarkLayer";
|
|
15
|
+
const MapleMarkLayer = forwardRef(function MapleMarkLayer(props, ref) {
|
|
16
|
+
const { className } = props;
|
|
17
|
+
const { container } = useMapleUi(PART);
|
|
18
|
+
const state = useMaple();
|
|
19
|
+
const client = useMapleClient();
|
|
20
|
+
const chosen = props.onSelect;
|
|
21
|
+
const onSelect = useCallback((comment) => {
|
|
22
|
+
if (chosen) return chosen(comment);
|
|
23
|
+
client.viewComment(comment.id);
|
|
24
|
+
}, [chosen, client]);
|
|
25
|
+
const comments = props.comments ?? state.comments;
|
|
26
|
+
const visible = props.visible ?? state.visible;
|
|
27
|
+
const selectedId = props.selectedId ?? state.selected ?? void 0;
|
|
28
|
+
const peeked = state.peeked ?? void 0;
|
|
29
|
+
const address = useMemo(() => addresses(comments), [comments]);
|
|
30
|
+
const placed = useMemo(() => placements(visible, address, container.ownerDocument), [
|
|
31
|
+
visible,
|
|
32
|
+
address,
|
|
33
|
+
container
|
|
34
|
+
]);
|
|
35
|
+
const nudges = useNudges();
|
|
36
|
+
const nodes = useRef(/* @__PURE__ */ new Map());
|
|
37
|
+
const paint = useCallback(() => {
|
|
38
|
+
const height = viewportHeight(container);
|
|
39
|
+
const taken = [];
|
|
40
|
+
for (const placement of placed) {
|
|
41
|
+
const node = nodes.current.get(placement.comment.id);
|
|
42
|
+
const moved = nudges.of(placement.comment.id);
|
|
43
|
+
if (node) taken.push(step(node, placement, {
|
|
44
|
+
height,
|
|
45
|
+
taken,
|
|
46
|
+
...moved ? { moved } : {}
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
}, [
|
|
50
|
+
container,
|
|
51
|
+
nudges,
|
|
52
|
+
placed
|
|
53
|
+
]);
|
|
54
|
+
useFrameLoop(PART, paint);
|
|
55
|
+
useScrollTo(placed, selectedId);
|
|
56
|
+
const marks = useMemo(() => placed.map((placement) => createElement(MapleMark, {
|
|
57
|
+
...markProps(placement, {
|
|
58
|
+
selectedId,
|
|
59
|
+
peeked,
|
|
60
|
+
nudges
|
|
61
|
+
}),
|
|
62
|
+
...nudges.handlersFor(placement.comment.id),
|
|
63
|
+
key: placement.comment.id,
|
|
64
|
+
ref: keep(nodes.current, placement.comment.id),
|
|
65
|
+
onClick: () => onSelect(placement.comment),
|
|
66
|
+
onPointerEnter: () => client.peek(placement.comment.id),
|
|
67
|
+
onPointerLeave: () => client.peek(null),
|
|
68
|
+
onFocus: () => client.peek(placement.comment.id),
|
|
69
|
+
onBlur: () => client.peek(null)
|
|
70
|
+
})), [
|
|
71
|
+
client,
|
|
72
|
+
nudges,
|
|
73
|
+
onSelect,
|
|
74
|
+
peeked,
|
|
75
|
+
placed,
|
|
76
|
+
selectedId
|
|
77
|
+
]);
|
|
78
|
+
return createElement("div", {
|
|
79
|
+
className: className ? `mk-marks ${className}` : "mk-marks",
|
|
80
|
+
ref
|
|
81
|
+
}, ...marks, createElement(MapleTargetRing, ringFor({
|
|
82
|
+
client: state,
|
|
83
|
+
placed,
|
|
84
|
+
pointing: {
|
|
85
|
+
peeked,
|
|
86
|
+
selected: selectedId
|
|
87
|
+
},
|
|
88
|
+
root: container.ownerDocument
|
|
89
|
+
})));
|
|
90
|
+
});
|
|
91
|
+
function useScrollTo(placed, selectedId) {
|
|
92
|
+
const target = placed.find((placement) => placement.comment.id === selectedId)?.element;
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
target?.scrollIntoView({
|
|
95
|
+
block: "center",
|
|
96
|
+
inline: "nearest",
|
|
97
|
+
behavior: "smooth"
|
|
98
|
+
});
|
|
99
|
+
}, [target]);
|
|
100
|
+
}
|
|
101
|
+
function boxOf(placement) {
|
|
102
|
+
const box = placement.range?.getBoundingClientRect() ?? placement.element.getBoundingClientRect();
|
|
103
|
+
return placement.region === void 0 ? box : regionBox(box, placement.region);
|
|
104
|
+
}
|
|
105
|
+
function step(node, placement, frame) {
|
|
106
|
+
const rect = boxOf(placement);
|
|
107
|
+
const away = culled(rect, frame.height);
|
|
108
|
+
flag(node, OFF_ATTRIBUTE, away);
|
|
109
|
+
const wanted = markSpot(rect);
|
|
110
|
+
const spot = frame.moved ? {
|
|
111
|
+
...wanted,
|
|
112
|
+
x: wanted.x + frame.moved.dx,
|
|
113
|
+
y: wanted.y + frame.moved.dy
|
|
114
|
+
} : placeMark(wanted, frame.taken);
|
|
115
|
+
if (!away) place(node, spot);
|
|
116
|
+
return spot;
|
|
117
|
+
}
|
|
118
|
+
function keep(nodes, id) {
|
|
119
|
+
return (node) => {
|
|
120
|
+
if (node) nodes.set(id, node);
|
|
121
|
+
else nodes.delete(id);
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function markProps(placement, view) {
|
|
125
|
+
const { comment } = placement;
|
|
126
|
+
return {
|
|
127
|
+
address: placement.address,
|
|
128
|
+
status: comment.status,
|
|
129
|
+
confidence: placement.confidence,
|
|
130
|
+
author: comment.author.name,
|
|
131
|
+
on: ringLabel({
|
|
132
|
+
kind: kindOf(comment.anchor),
|
|
133
|
+
element: placement.element
|
|
134
|
+
}),
|
|
135
|
+
selected: comment.id === view.selectedId,
|
|
136
|
+
peeked: comment.id === view.peeked,
|
|
137
|
+
nudged: view.nudges.of(comment.id) !== void 0,
|
|
138
|
+
dragging: view.nudges.dragging === comment.id,
|
|
139
|
+
...comment.author.colorSlot === void 0 ? {} : { colorSlot: comment.author.colorSlot }
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function ringFor(input) {
|
|
143
|
+
const peeked = marked(input, input.pointing.peeked, "hovered");
|
|
144
|
+
if (peeked) return peeked;
|
|
145
|
+
const { composer } = input.client;
|
|
146
|
+
if (composer.open && composer.target) return composing(composer.target, input);
|
|
147
|
+
return marked(input, input.pointing.selected, "selected") ?? {};
|
|
148
|
+
}
|
|
149
|
+
function marked(input, id, state) {
|
|
150
|
+
const hit = input.placed.find((placement) => placement.comment.id === id);
|
|
151
|
+
if (!hit) return void 0;
|
|
152
|
+
return {
|
|
153
|
+
target: hit.range ?? hit.element,
|
|
154
|
+
...hit.region === void 0 ? {} : { region: hit.region },
|
|
155
|
+
label: ringLabel({
|
|
156
|
+
kind: kindOf(hit.comment.anchor),
|
|
157
|
+
element: hit.element
|
|
158
|
+
}),
|
|
159
|
+
...noteFor({
|
|
160
|
+
anchor: hit.comment.anchor,
|
|
161
|
+
element: hit.element
|
|
162
|
+
}, input.client.detail),
|
|
163
|
+
state
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function composing(target, input) {
|
|
167
|
+
const found = resolveAnchor(target.anchor, {
|
|
168
|
+
root: input.root,
|
|
169
|
+
passage: target.kind === "text"
|
|
170
|
+
});
|
|
171
|
+
const label = ringLabel({
|
|
172
|
+
kind: target.kind,
|
|
173
|
+
anchor: target.anchor,
|
|
174
|
+
...target.label === void 0 ? {} : { named: target.label },
|
|
175
|
+
...found.status === "resolved" ? { element: found.element } : {}
|
|
176
|
+
});
|
|
177
|
+
if (found.status !== "resolved") return {};
|
|
178
|
+
return {
|
|
179
|
+
target: found.range ?? found.element,
|
|
180
|
+
...target.anchor.region === void 0 ? {} : { region: target.anchor.region },
|
|
181
|
+
label,
|
|
182
|
+
...noteFor({
|
|
183
|
+
anchor: target.anchor,
|
|
184
|
+
element: found.element
|
|
185
|
+
}, input.client.detail),
|
|
186
|
+
state: input.client.composer.viewing === void 0 ? "composing" : "selected"
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function noteFor(source, detail) {
|
|
190
|
+
const note = detail === "developer" ? sourceFor(source) : void 0;
|
|
191
|
+
return note === void 0 ? {} : { note };
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
export { MapleMarkLayer };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/marks/leaf.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The leaf, as path data. Assets, not code.
|
|
4
|
+
*
|
|
5
|
+
* `LEAF_OUTLINE` is two subpaths — the silhouette and its inner counter — so
|
|
6
|
+
* the outline form needs no stroke and recolours with one `fill`. The view box
|
|
7
|
+
* is the rotated bounding box: the unrotated 64-unit box clips the tips at 20
|
|
8
|
+
* degrees, which is the one thing that looks broken rather than merely wrong.
|
|
9
|
+
*/
|
|
10
|
+
/** The rotated bounding box. Anything smaller clips the tips. */
|
|
11
|
+
export declare const LEAF_VIEW_BOX = "-7 -7 78 78";
|
|
12
|
+
/** Every path is wrapped in this, about the centre of the unrotated box. */
|
|
13
|
+
export declare const LEAF_ROTATION = "rotate(20 32 32)";
|
|
14
|
+
/** The filled silhouette. */
|
|
15
|
+
export declare const LEAF_SOLID = "m56.97 32.46c-1.32-0.74-2.03-1.54-2.03-2.85 0-2.32 2.43-5.26 2.23-6.55-0.09-0.83-1.03-1.48-2.24-1.48-1.33 0-2.76 0.42-4.02 0.42-1.25 0-1.84-0.44-2.52-0.44-1.84 0-3.19 2.52-4.74 2.52-1.13 0-1.72-0.95-1.72-2.42 0-1.92 0.8-4.43 0.8-6.43 0-2.43-1.02-3.33-2.77-3.82-1.89-0.52-2.99-1.31-4.37-4.07-0.99-2.04-2.1-3.34-3.3-3.34-1.1 0-2.2 1.55-3.08 3.34-1.31 2.65-2.53 3.62-4.57 4.18-1.83 0.5-2.7 1.54-2.7 3.73 0 2.16 0.8 4.6 0.8 6.49 0 1.59-0.75 2.44-1.77 2.44-1.56 0-3.36-2.6-5.07-2.6-0.81 0-1.59 0.42-2.69 0.42-1.19 0-2.61-0.41-3.86-0.41-1.28 0-2.19 0.68-2.19 1.62 0 1.68 2.17 4.06 2.17 6.36 0 1.49-0.92 2.25-2.25 2.97-0.66 0.36-0.96 0.68-0.96 1.21 0 0.74 1.4 1.93 4 3.74 3.44 2.42 5.37 2.72 6.31 3.58 0.29 0.27 0.42 0.58 0.42 1.11 0 1.65-3.42 4.11-3.42 5.6 0 1.13 1.5 1.5 3.88 1.57 2.14 0.05 3.64 0.2 4.42 0.88 0.53 0.45 1.08 0.7 1.71 0.7 2.38 0 5.9-2.9 7.08-2.9 0.42 0 0.54 0.3 0.54 1.09 0 3.68-0.92 7.36-0.92 8.84 0 1.37 0.78 2.04 1.73 2.04 0.98 0 1.78-0.89 1.78-2.29 0-2.08-0.55-5.02-0.55-8.11 0-1.24 0.16-1.57 0.7-1.57 1.12 0 4.93 2.9 7.01 2.9 0.6 0 1.15-0.24 1.63-0.66 0.82-0.69 2.38-0.85 4.48-0.89 2.57-0.05 3.82-0.51 3.82-1.58 0-1.34-3.1-3.7-3.1-5.44 0-0.89 0.65-1.56 1.93-2.09 1.79-0.76 4.26-2.35 6.27-3.89 1.63-1.25 2.39-1.96 2.39-2.62 0-0.51-0.48-0.88-1.26-1.3z";
|
|
16
|
+
/** The ring: silhouette plus counter, filled rather than stroked. */
|
|
17
|
+
export declare const LEAF_OUTLINE = "m56.99 32.75c-1.36-0.576-2.44-1.416-2.44-2.584 0-1.304 2.472-4.976 2.472-6.064 0-0.88-1-1.208-1.952-1.208-1.936 0-4.496 1.472-6.04 1.472-1.648 0-1.536-1.8-2.728-1.8-1.144 0-3.512 2.8-4.944 2.8-0.8 0-1.072-0.728-1.072-1.712 0-2.128 1.744-6.76 1.744-8.424 0-1.816-1.32-2.192-2.936-2.416-4.264-0.608-5.072-7.64-7.272-7.64-1.432 0-2.544 2.6-3.576 4.656-0.952 1.888-2.096 2.928-4.096 3.272-1.632 0.28-2.36 1.008-2.36 2.488 0 1.88 1.632 6.12 1.632 8.56 0 0.944-0.352 1.48-0.992 1.48-1.688 0-3.736-2.952-5.032-2.952-1.16 0-1.064 1.84-2.72 1.84-1.488 0-4.104-1.336-5.728-1.336-1.28 0-2.088 0.464-2.088 1.264 0 1.032 2.512 4.52 2.512 5.976 0 1.504-1.656 2.224-2.72 2.632-0.456 0.176-0.656 0.512-0.656 0.904 0 0.808 1.504 1.84 3.752 3.744 3.36 2.88 6.456 3.672 6.456 5 0 1.928-3.888 4.752-3.888 5.744 0 0.656 0.768 0.808 1.832 0.928 2.136 0.24 4.496 0.376 6.08 1.712 0.616 0.512 1.272 0.912 1.952 0.912 2.192 0 6.832-3.088 7.592-3.088 0.48 0 0.584 0.624 0.584 2.088 0 2.576-0.392 5.168-0.392 6.184 0 1.504 1.088 2.04 2.072 2.04s1.912-0.616 1.912-1.92c0-1.36-0.432-3.528-0.432-5.528 0-2.136 0.168-2.856 0.64-2.856 0.88 0 5.352 3.072 7.368 3.072 0.704 0 1.336-0.424 1.984-0.928 2.08-1.68 7.288-1.384 7.84-2.32 0.184-0.312 0.096-0.696-0.264-1.208-1.04-1.504-3.408-3.4-3.408-4.792 0-1.248 1.944-2.056 4.52-3.928 1.52-1.104 2.728-2.232 4.112-3.2 1.056-0.744 1.664-1.272 1.664-1.888 0.016-0.464-0.432-0.752-0.984-0.976zm-1.28 2.2c-1.576 1.128-3.528 2.928-6.784 5-1.296 0.824-2.176 1.56-2.176 2.696 0 1.696 3.352 4.928 3.352 5.432 0 0.28-0.408 0.416-1.168 0.464-2.288 0.168-4.984 0.512-6.472 1.776-0.432 0.344-0.784 0.512-1.192 0.512-2.192 0-6.592-3-7.72-3-0.744 0-0.88 0.688-0.88 2.44 0 2.68 0.168 5.48 0.168 6.68 0 0.848-0.4 1.184-0.888 1.184-0.56 0-0.888-0.392-0.888-1.264 0-1.056 0.224-3.744 0.224-6.576 0-1.744-0.168-2.448-1.04-2.448-1.032 0-5.76 3.064-7.704 3.064-0.568 0-1.072-0.288-1.68-0.656-1.936-1.224-4.56-1.376-6.6-1.656-0.448-0.064-0.608-0.184-0.608-0.4 0-0.688 3.704-3.936 3.704-5.736 0-1.176-1.72-1.928-3.36-2.928-1.624-0.992-2.696-2.192-4.248-3.304-1.496-0.984-2.544-1.584-2.544-2.12 0-0.304 0.384-0.512 0.944-0.784 1.216-0.592 2.432-1.384 2.432-2.768 0-1.68-2.344-5.04-2.344-5.8 0-0.408 0.416-0.552 1.024-0.552 1.512 0 4.536 1.224 5.656 1.224 1.68 0 2.144-1.456 2.84-1.456 0.952 0 3.232 2.904 4.976 2.904 1.224 0 1.776-1.04 1.776-2.36 0-2.392-1.592-6.24-1.592-8.384 0-1.376 0.52-1.864 2.032-2.208 1.856-0.432 2.968-1.56 4.016-3.496 1.024-1.968 2.096-3.768 2.856-3.768 0.848 0 1.824 2.44 3.04 4.6 0.968 1.688 2.08 2.4 3.92 2.584 1.52 0.152 2.032 0.64 2.032 1.888 0 2.208-1.568 6.152-1.568 8.216 0 1.728 0.84 2.608 1.912 2.608 1.792 0 3.984-2.76 4.936-2.76 0.84 0 1.072 1.416 2.896 1.416 1.656 0 4.576-1.28 5.968-1.28 0.44 0 0.64 0.2 0.64 0.536 0 0.976-1.488 3.52-2.144 4.816-0.168 0.36-0.216 0.68-0.216 0.992 0 1.328 1.64 2.368 2.944 3.016 0.352 0.176 0.52 0.344 0.52 0.552-0.016 0.32-0.424 0.704-0.992 1.104z";
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/marks/leaf.ts
|
|
2
|
+
const LEAF_VIEW_BOX = "-7 -7 78 78";
|
|
3
|
+
const LEAF_ROTATION = "rotate(20 32 32)";
|
|
4
|
+
const LEAF_SOLID = "m56.97 32.46c-1.32-0.74-2.03-1.54-2.03-2.85 0-2.32 2.43-5.26 2.23-6.55-0.09-0.83-1.03-1.48-2.24-1.48-1.33 0-2.76 0.42-4.02 0.42-1.25 0-1.84-0.44-2.52-0.44-1.84 0-3.19 2.52-4.74 2.52-1.13 0-1.72-0.95-1.72-2.42 0-1.92 0.8-4.43 0.8-6.43 0-2.43-1.02-3.33-2.77-3.82-1.89-0.52-2.99-1.31-4.37-4.07-0.99-2.04-2.1-3.34-3.3-3.34-1.1 0-2.2 1.55-3.08 3.34-1.31 2.65-2.53 3.62-4.57 4.18-1.83 0.5-2.7 1.54-2.7 3.73 0 2.16 0.8 4.6 0.8 6.49 0 1.59-0.75 2.44-1.77 2.44-1.56 0-3.36-2.6-5.07-2.6-0.81 0-1.59 0.42-2.69 0.42-1.19 0-2.61-0.41-3.86-0.41-1.28 0-2.19 0.68-2.19 1.62 0 1.68 2.17 4.06 2.17 6.36 0 1.49-0.92 2.25-2.25 2.97-0.66 0.36-0.96 0.68-0.96 1.21 0 0.74 1.4 1.93 4 3.74 3.44 2.42 5.37 2.72 6.31 3.58 0.29 0.27 0.42 0.58 0.42 1.11 0 1.65-3.42 4.11-3.42 5.6 0 1.13 1.5 1.5 3.88 1.57 2.14 0.05 3.64 0.2 4.42 0.88 0.53 0.45 1.08 0.7 1.71 0.7 2.38 0 5.9-2.9 7.08-2.9 0.42 0 0.54 0.3 0.54 1.09 0 3.68-0.92 7.36-0.92 8.84 0 1.37 0.78 2.04 1.73 2.04 0.98 0 1.78-0.89 1.78-2.29 0-2.08-0.55-5.02-0.55-8.11 0-1.24 0.16-1.57 0.7-1.57 1.12 0 4.93 2.9 7.01 2.9 0.6 0 1.15-0.24 1.63-0.66 0.82-0.69 2.38-0.85 4.48-0.89 2.57-0.05 3.82-0.51 3.82-1.58 0-1.34-3.1-3.7-3.1-5.44 0-0.89 0.65-1.56 1.93-2.09 1.79-0.76 4.26-2.35 6.27-3.89 1.63-1.25 2.39-1.96 2.39-2.62 0-0.51-0.48-0.88-1.26-1.3z";
|
|
5
|
+
const LEAF_OUTLINE = "m56.99 32.75c-1.36-0.576-2.44-1.416-2.44-2.584 0-1.304 2.472-4.976 2.472-6.064 0-0.88-1-1.208-1.952-1.208-1.936 0-4.496 1.472-6.04 1.472-1.648 0-1.536-1.8-2.728-1.8-1.144 0-3.512 2.8-4.944 2.8-0.8 0-1.072-0.728-1.072-1.712 0-2.128 1.744-6.76 1.744-8.424 0-1.816-1.32-2.192-2.936-2.416-4.264-0.608-5.072-7.64-7.272-7.64-1.432 0-2.544 2.6-3.576 4.656-0.952 1.888-2.096 2.928-4.096 3.272-1.632 0.28-2.36 1.008-2.36 2.488 0 1.88 1.632 6.12 1.632 8.56 0 0.944-0.352 1.48-0.992 1.48-1.688 0-3.736-2.952-5.032-2.952-1.16 0-1.064 1.84-2.72 1.84-1.488 0-4.104-1.336-5.728-1.336-1.28 0-2.088 0.464-2.088 1.264 0 1.032 2.512 4.52 2.512 5.976 0 1.504-1.656 2.224-2.72 2.632-0.456 0.176-0.656 0.512-0.656 0.904 0 0.808 1.504 1.84 3.752 3.744 3.36 2.88 6.456 3.672 6.456 5 0 1.928-3.888 4.752-3.888 5.744 0 0.656 0.768 0.808 1.832 0.928 2.136 0.24 4.496 0.376 6.08 1.712 0.616 0.512 1.272 0.912 1.952 0.912 2.192 0 6.832-3.088 7.592-3.088 0.48 0 0.584 0.624 0.584 2.088 0 2.576-0.392 5.168-0.392 6.184 0 1.504 1.088 2.04 2.072 2.04s1.912-0.616 1.912-1.92c0-1.36-0.432-3.528-0.432-5.528 0-2.136 0.168-2.856 0.64-2.856 0.88 0 5.352 3.072 7.368 3.072 0.704 0 1.336-0.424 1.984-0.928 2.08-1.68 7.288-1.384 7.84-2.32 0.184-0.312 0.096-0.696-0.264-1.208-1.04-1.504-3.408-3.4-3.408-4.792 0-1.248 1.944-2.056 4.52-3.928 1.52-1.104 2.728-2.232 4.112-3.2 1.056-0.744 1.664-1.272 1.664-1.888 0.016-0.464-0.432-0.752-0.984-0.976zm-1.28 2.2c-1.576 1.128-3.528 2.928-6.784 5-1.296 0.824-2.176 1.56-2.176 2.696 0 1.696 3.352 4.928 3.352 5.432 0 0.28-0.408 0.416-1.168 0.464-2.288 0.168-4.984 0.512-6.472 1.776-0.432 0.344-0.784 0.512-1.192 0.512-2.192 0-6.592-3-7.72-3-0.744 0-0.88 0.688-0.88 2.44 0 2.68 0.168 5.48 0.168 6.68 0 0.848-0.4 1.184-0.888 1.184-0.56 0-0.888-0.392-0.888-1.264 0-1.056 0.224-3.744 0.224-6.576 0-1.744-0.168-2.448-1.04-2.448-1.032 0-5.76 3.064-7.704 3.064-0.568 0-1.072-0.288-1.68-0.656-1.936-1.224-4.56-1.376-6.6-1.656-0.448-0.064-0.608-0.184-0.608-0.4 0-0.688 3.704-3.936 3.704-5.736 0-1.176-1.72-1.928-3.36-2.928-1.624-0.992-2.696-2.192-4.248-3.304-1.496-0.984-2.544-1.584-2.544-2.12 0-0.304 0.384-0.512 0.944-0.784 1.216-0.592 2.432-1.384 2.432-2.768 0-1.68-2.344-5.04-2.344-5.8 0-0.408 0.416-0.552 1.024-0.552 1.512 0 4.536 1.224 5.656 1.224 1.68 0 2.144-1.456 2.84-1.456 0.952 0 3.232 2.904 4.976 2.904 1.224 0 1.776-1.04 1.776-2.36 0-2.392-1.592-6.24-1.592-8.384 0-1.376 0.52-1.864 2.032-2.208 1.856-0.432 2.968-1.56 4.016-3.496 1.024-1.968 2.096-3.768 2.856-3.768 0.848 0 1.824 2.44 3.04 4.6 0.968 1.688 2.08 2.4 3.92 2.584 1.52 0.152 2.032 0.64 2.032 1.888 0 2.208-1.568 6.152-1.568 8.216 0 1.728 0.84 2.608 1.912 2.608 1.792 0 3.984-2.76 4.936-2.76 0.84 0 1.072 1.416 2.896 1.416 1.656 0 4.576-1.28 5.968-1.28 0.44 0 0.64 0.2 0.64 0.536 0 0.976-1.488 3.52-2.144 4.816-0.168 0.36-0.216 0.68-0.216 0.992 0 1.328 1.64 2.368 2.944 3.016 0.352 0.176 0.52 0.344 0.52 0.552-0.016 0.32-0.424 0.704-0.992 1.104z";
|
|
6
|
+
//#endregion
|
|
7
|
+
export { LEAF_OUTLINE, LEAF_ROTATION, LEAF_SOLID, LEAF_VIEW_BOX };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AsChildProps } from "../slot.js";
|
|
2
|
+
import { ButtonHTMLAttributes } from "react";
|
|
3
|
+
import { CommentStatus } from "@maple-kit/core";
|
|
4
|
+
//#region src/marks/mark.d.ts
|
|
5
|
+
/** Everything the mark says, and nothing about how it should look. */
|
|
6
|
+
export interface MarkProps extends AsChildProps, ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
/** The address: the number the list and the export table also show. */
|
|
8
|
+
readonly address: number;
|
|
9
|
+
readonly status?: CommentStatus;
|
|
10
|
+
/** False for a comment still being written, which is the dashed form. */
|
|
11
|
+
readonly sent?: boolean;
|
|
12
|
+
/** How sure the anchor is, 0 to 1. A weak one draws a translucent fill. */
|
|
13
|
+
readonly confidence?: number;
|
|
14
|
+
/** The author's reviewer colour, 0 to 9. Absent leaves the status colour. */
|
|
15
|
+
readonly colorSlot?: number;
|
|
16
|
+
readonly author?: string;
|
|
17
|
+
/** What it is on, for the tooltip: "the Yield card". */
|
|
18
|
+
readonly on?: string;
|
|
19
|
+
readonly selected?: boolean;
|
|
20
|
+
/** A row or the mark itself is being pointed at. Sticks to nothing. */
|
|
21
|
+
readonly peeked?: boolean;
|
|
22
|
+
/** Someone moved it off what it was covering, and it holds where they put it. */
|
|
23
|
+
readonly nudged?: boolean;
|
|
24
|
+
readonly dragging?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** A mark a reviewer can click, drawn from state that arrives as `data-*`. */
|
|
27
|
+
export declare const MapleMark: import("react").ForwardRefExoticComponent<MarkProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
28
|
+
//#endregion
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { confidenceFor, dataAttributes, formFor, pointerAttributes } from "../data.js";
|
|
2
|
+
import { Slot, composeRefs } from "../slot.js";
|
|
3
|
+
import { applyReviewerSlot } from "../slots.js";
|
|
4
|
+
import { MapleLeaf, inside } from "./shape.js";
|
|
5
|
+
import { markLabel, markTitle } from "./label.js";
|
|
6
|
+
import { createElement, forwardRef, useCallback } from "react";
|
|
7
|
+
//#region src/marks/mark.ts
|
|
8
|
+
const MapleMark = forwardRef(function MapleMark(props, ref) {
|
|
9
|
+
const { address, asChild, author, children, className, colorSlot, confidence, dragging, nudged, on, peeked, selected, sent, status = "open", ...rest } = props;
|
|
10
|
+
const form = formFor(status, sent ?? true);
|
|
11
|
+
const paint = useCallback((node) => {
|
|
12
|
+
if (node && colorSlot !== void 0) applyReviewerSlot(node, colorSlot);
|
|
13
|
+
}, [colorSlot]);
|
|
14
|
+
return createElement(asChild ? Slot : "button", {
|
|
15
|
+
type: "button",
|
|
16
|
+
...rest,
|
|
17
|
+
...dataAttributes({
|
|
18
|
+
status,
|
|
19
|
+
form,
|
|
20
|
+
sent: sent ?? true,
|
|
21
|
+
...confidence === void 0 ? {} : { confidence: confidenceFor(confidence) }
|
|
22
|
+
}),
|
|
23
|
+
...pointerAttributes({
|
|
24
|
+
peeked: peeked ?? false,
|
|
25
|
+
nudged: nudged ?? false,
|
|
26
|
+
dragging: dragging ?? false
|
|
27
|
+
}),
|
|
28
|
+
"aria-label": markLabel(address, author, status),
|
|
29
|
+
"aria-pressed": selected ?? false,
|
|
30
|
+
title: markTitle(author, status, on),
|
|
31
|
+
className: className ? `mk-mark mk-hit ${className}` : "mk-mark mk-hit",
|
|
32
|
+
ref: composeRefs(ref, paint)
|
|
33
|
+
}, ...inside(asChild, children, [createElement(MapleLeaf, {
|
|
34
|
+
key: "leaf",
|
|
35
|
+
form
|
|
36
|
+
}), createElement("span", {
|
|
37
|
+
key: "n",
|
|
38
|
+
className: "mk-mark-n mk-num",
|
|
39
|
+
"data-mk-digits": String(String(address).length)
|
|
40
|
+
}, address)]));
|
|
41
|
+
});
|
|
42
|
+
//#endregion
|
|
43
|
+
export { MapleMark };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//#region src/marks/nudge.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Moving a mark off what it is covering, without moving what it is about.
|
|
4
|
+
*
|
|
5
|
+
* A mark stands just outside its anchor's corner, and sometimes that corner is
|
|
6
|
+
* the one thing on the page worth reading. The offset is the reviewer's, not
|
|
7
|
+
* the comment's: it is held for the session, never recorded, and never sent —
|
|
8
|
+
* where a mark was dragged to says nothing about where the comment belongs.
|
|
9
|
+
* The collision resolver stands down for a nudged mark, because a mark that
|
|
10
|
+
* was put somewhere on purpose is not one to be stepped sideways.
|
|
11
|
+
*/
|
|
12
|
+
/** Under this, a pointer went down and up on a mark, which is a click. */
|
|
13
|
+
export declare const NUDGE_THRESHOLD_PX = 4;
|
|
14
|
+
/** As far as a mark goes. Past this it names something it is not beside. */
|
|
15
|
+
export declare const NUDGE_LIMIT_PX = 160;
|
|
16
|
+
/** How far a mark has been moved from where its anchor puts it. */
|
|
17
|
+
export interface Nudge {
|
|
18
|
+
readonly dx: number;
|
|
19
|
+
readonly dy: number;
|
|
20
|
+
}
|
|
21
|
+
/** Kept inside the limit on both axes, so a mark stays near its anchor. */
|
|
22
|
+
export declare function clampNudge(nudge: Nudge): Nudge;
|
|
23
|
+
/** True once the pointer has travelled far enough to be a drag, not a click. */
|
|
24
|
+
export declare function dragged(from: Nudge): boolean;
|
|
25
|
+
/** The parts of a pointer event a nudge needs. Structural, so it tests flat. */
|
|
26
|
+
export interface NudgePointer {
|
|
27
|
+
readonly clientX: number;
|
|
28
|
+
readonly clientY: number;
|
|
29
|
+
/** Absent on the click that ends a drag, which is a mouse event. */
|
|
30
|
+
readonly pointerId?: number;
|
|
31
|
+
readonly currentTarget: EventTarget | null;
|
|
32
|
+
preventDefault?(): void;
|
|
33
|
+
stopPropagation?(): void;
|
|
34
|
+
}
|
|
35
|
+
/** What one mark spreads to become draggable. */
|
|
36
|
+
export interface NudgeHandlers {
|
|
37
|
+
readonly onPointerDown: (event: NudgePointer) => void;
|
|
38
|
+
readonly onPointerMove: (event: NudgePointer) => void;
|
|
39
|
+
readonly onPointerUp: (event: NudgePointer) => void;
|
|
40
|
+
readonly onClickCapture: (event: NudgePointer) => void;
|
|
41
|
+
}
|
|
42
|
+
/** Every mark's offset, and the handlers that change one. */
|
|
43
|
+
export interface Nudges {
|
|
44
|
+
readonly of: (id: string) => Nudge | undefined;
|
|
45
|
+
readonly dragging: string | undefined;
|
|
46
|
+
readonly handlersFor: (id: string) => NudgeHandlers;
|
|
47
|
+
}
|
|
48
|
+
/** The session's offsets. Nothing here reaches storage or the controller. */
|
|
49
|
+
export declare function useNudges(): Nudges;
|
|
50
|
+
//#endregion
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from "react";
|
|
2
|
+
//#region src/marks/nudge.ts
|
|
3
|
+
const NUDGE_THRESHOLD_PX = 4;
|
|
4
|
+
const NUDGE_LIMIT_PX = 160;
|
|
5
|
+
function clampNudge(nudge) {
|
|
6
|
+
const hold = (value) => Math.max(-160, Math.min(160, value));
|
|
7
|
+
return {
|
|
8
|
+
dx: hold(nudge.dx),
|
|
9
|
+
dy: hold(nudge.dy)
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function dragged(from) {
|
|
13
|
+
return Math.abs(from.dx) >= 4 || Math.abs(from.dy) >= 4;
|
|
14
|
+
}
|
|
15
|
+
function useNudges() {
|
|
16
|
+
const [offsets, setOffsets] = useState(/* @__PURE__ */ new Map());
|
|
17
|
+
const [dragging, setDragging] = useState();
|
|
18
|
+
const drag = useRef(void 0);
|
|
19
|
+
const move = useCallback((id, next) => {
|
|
20
|
+
setOffsets((was) => new Map(was).set(id, clampNudge(next)));
|
|
21
|
+
}, []);
|
|
22
|
+
const handlersFor = useCallback((id) => ({
|
|
23
|
+
onPointerDown: (event) => {
|
|
24
|
+
const node = event.currentTarget;
|
|
25
|
+
if (node instanceof Element && event.pointerId !== void 0) node.setPointerCapture(event.pointerId);
|
|
26
|
+
drag.current = {
|
|
27
|
+
id,
|
|
28
|
+
from: {
|
|
29
|
+
x: event.clientX,
|
|
30
|
+
y: event.clientY
|
|
31
|
+
},
|
|
32
|
+
base: offsets.get(id) ?? {
|
|
33
|
+
dx: 0,
|
|
34
|
+
dy: 0
|
|
35
|
+
},
|
|
36
|
+
moved: false
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
onPointerMove: (event) => {
|
|
40
|
+
const held = drag.current;
|
|
41
|
+
if (held?.id !== id) return;
|
|
42
|
+
const travelled = {
|
|
43
|
+
dx: event.clientX - held.from.x,
|
|
44
|
+
dy: event.clientY - held.from.y
|
|
45
|
+
};
|
|
46
|
+
if (!held.moved && !dragged(travelled)) return;
|
|
47
|
+
held.moved = true;
|
|
48
|
+
setDragging(id);
|
|
49
|
+
move(id, {
|
|
50
|
+
dx: held.base.dx + travelled.dx,
|
|
51
|
+
dy: held.base.dy + travelled.dy
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
onPointerUp: () => {
|
|
55
|
+
setDragging(void 0);
|
|
56
|
+
if (drag.current?.id === id && !drag.current.moved) drag.current = void 0;
|
|
57
|
+
},
|
|
58
|
+
onClickCapture: (event) => {
|
|
59
|
+
if (drag.current?.id !== id || !drag.current.moved) return;
|
|
60
|
+
drag.current = void 0;
|
|
61
|
+
event.preventDefault?.();
|
|
62
|
+
event.stopPropagation?.();
|
|
63
|
+
}
|
|
64
|
+
}), [move, offsets]);
|
|
65
|
+
return useMemo(() => ({
|
|
66
|
+
of: (id) => offsets.get(id),
|
|
67
|
+
dragging,
|
|
68
|
+
handlersFor
|
|
69
|
+
}), [
|
|
70
|
+
dragging,
|
|
71
|
+
handlersFor,
|
|
72
|
+
offsets
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { NUDGE_LIMIT_PX, NUDGE_THRESHOLD_PX, clampNudge, dragged, useNudges };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Box } from "./geometry.js";
|
|
2
|
+
//#region src/marks/paint.d.ts
|
|
3
|
+
/** Set while something is being repositioned, and only then. */
|
|
4
|
+
export declare const MOVING_ATTRIBUTE = "data-mk-moving";
|
|
5
|
+
/** Set on anything scrolled far enough off-screen to stop drawing. */
|
|
6
|
+
export declare const OFF_ATTRIBUTE = "data-mk-off";
|
|
7
|
+
/** Moves one node. Rounding is the caller's, so a box is measured once. */
|
|
8
|
+
export declare function place(node: ElementCSSInlineStyle, box: Box): void;
|
|
9
|
+
/** Writes an attribute only when it would change, so a frame costs nothing. */
|
|
10
|
+
export declare function flag(node: Element, attribute: string, on: boolean): void;
|
|
11
|
+
//#endregion
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/marks/paint.ts
|
|
2
|
+
const X_PROPERTY = "--mk-x";
|
|
3
|
+
const Y_PROPERTY = "--mk-y";
|
|
4
|
+
const W_PROPERTY = "--mk-w";
|
|
5
|
+
const H_PROPERTY = "--mk-h";
|
|
6
|
+
const MOVING_ATTRIBUTE = "data-mk-moving";
|
|
7
|
+
const OFF_ATTRIBUTE = "data-mk-off";
|
|
8
|
+
function place(node, box) {
|
|
9
|
+
const { style } = node;
|
|
10
|
+
style.setProperty(X_PROPERTY, `${box.x}px`);
|
|
11
|
+
style.setProperty(Y_PROPERTY, `${box.y}px`);
|
|
12
|
+
style.setProperty(W_PROPERTY, `${box.width}px`);
|
|
13
|
+
style.setProperty(H_PROPERTY, `${box.height}px`);
|
|
14
|
+
}
|
|
15
|
+
function flag(node, attribute, on) {
|
|
16
|
+
if (node.hasAttribute(attribute) !== on) node.toggleAttribute(attribute, on);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { H_PROPERTY, MOVING_ATTRIBUTE, OFF_ATTRIBUTE, W_PROPERTY, X_PROPERTY, Y_PROPERTY, flag, place };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AnchorRegion } from "@maple-kit/core/anchor";
|
|
2
|
+
import { Comment } from "@maple-kit/core";
|
|
3
|
+
//#region src/marks/placement.d.ts
|
|
4
|
+
/** A comment the page still has somewhere to put. */
|
|
5
|
+
export interface Placement {
|
|
6
|
+
readonly comment: Comment;
|
|
7
|
+
/** The address: its place in the branch's own order, counted from one. */
|
|
8
|
+
readonly address: number;
|
|
9
|
+
readonly element: Element;
|
|
10
|
+
/** The passage itself, when a text rung placed it. */
|
|
11
|
+
readonly range?: Range;
|
|
12
|
+
/** The rectangle, when the comment is on a region rather than an element. */
|
|
13
|
+
readonly region?: AnchorRegion;
|
|
14
|
+
readonly confidence: number;
|
|
15
|
+
}
|
|
16
|
+
/** The address of every comment, which the list and the export share. */
|
|
17
|
+
export declare function addresses(comments: readonly Comment[]): ReadonlyMap<string, number>;
|
|
18
|
+
/**
|
|
19
|
+
* Everything drawable, in the order it was given, with nothing guessed. A text
|
|
20
|
+
* anchor is narrowed to its passage, so the ring a mark draws highlights the
|
|
21
|
+
* words the comment is on rather than the paragraph they sit in.
|
|
22
|
+
*/
|
|
23
|
+
export declare function placements(comments: readonly Comment[], address: ReadonlyMap<string, number>, root: ParentNode): readonly Placement[];
|
|
24
|
+
//#endregion
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { kindOf, resolveAnchor } from "@maple-kit/core/anchor";
|
|
2
|
+
//#region src/marks/placement.ts
|
|
3
|
+
function addresses(comments) {
|
|
4
|
+
return new Map(comments.map((comment, index) => [comment.id, index + 1]));
|
|
5
|
+
}
|
|
6
|
+
function placements(comments, address, root) {
|
|
7
|
+
const placed = [];
|
|
8
|
+
for (const comment of comments) {
|
|
9
|
+
if (comment.status === "orphaned") continue;
|
|
10
|
+
const passage = kindOf(comment.anchor) === "text";
|
|
11
|
+
const found = resolveAnchor(comment.anchor, {
|
|
12
|
+
root,
|
|
13
|
+
passage
|
|
14
|
+
});
|
|
15
|
+
if (found.status !== "resolved") continue;
|
|
16
|
+
placed.push({
|
|
17
|
+
comment,
|
|
18
|
+
address: address.get(comment.id) ?? 0,
|
|
19
|
+
element: found.element,
|
|
20
|
+
...found.range === void 0 ? {} : { range: found.range },
|
|
21
|
+
...comment.anchor.region === void 0 ? {} : { region: comment.anchor.region },
|
|
22
|
+
confidence: found.confidence
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return placed;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { addresses, placements };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AnchorRegion } from "@maple-kit/core/anchor";
|
|
2
|
+
//#region src/marks/ring.d.ts
|
|
3
|
+
/** Set on the label when the anchor is too near the top to sit above it. */
|
|
4
|
+
export declare const BELOW_ATTRIBUTE = "data-mk-below";
|
|
5
|
+
/**
|
|
6
|
+
* Why the ring is showing. `selected` is the one that outlives the pointer:
|
|
7
|
+
* a click holds the ring on the page after the hand has moved away.
|
|
8
|
+
*/
|
|
9
|
+
export type RingState = "composing" | "hovered" | "selected";
|
|
10
|
+
/** What the ring names, and the words it names it with. */
|
|
11
|
+
export interface TargetRingProps {
|
|
12
|
+
/** The anchored element, or the passage itself when it is a text anchor. */
|
|
13
|
+
readonly target?: Element | Range | null;
|
|
14
|
+
/**
|
|
15
|
+
* The rectangle a region pick drew, in fractions of the target's box. The
|
|
16
|
+
* ring is that rectangle rather than the element it was measured in.
|
|
17
|
+
*/
|
|
18
|
+
readonly region?: AnchorRegion;
|
|
19
|
+
/** The label's words. `ringLabel` builds them; the ring never invents them. */
|
|
20
|
+
readonly label?: string;
|
|
21
|
+
/** A second line under the label. Developer detail: where this is written. */
|
|
22
|
+
readonly note?: string;
|
|
23
|
+
readonly state?: RingState;
|
|
24
|
+
readonly className?: string;
|
|
25
|
+
}
|
|
26
|
+
/** The ring around one target, repositioned per scrolled frame. */
|
|
27
|
+
export declare const MapleTargetRing: import("react").ForwardRefExoticComponent<TargetRingProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
28
|
+
//#endregion
|