@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
package/dist/data.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CommentStatus } from "@maple-kit/core";
|
|
2
|
+
//#region src/data.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* How a mark is drawn: fill says how far through a comment's life it is, so
|
|
5
|
+
* the leaf fills up rather than emptying out. Open is an outline, re-verify
|
|
6
|
+
* is half, resolved is full, and one never written is an outline too — in
|
|
7
|
+
* grey, which is what tells the two apart.
|
|
8
|
+
*/
|
|
9
|
+
export type PartForm = "outline" | "partial" | "solid";
|
|
10
|
+
/** The confidence word a reviewer reads, and what the low fill keys off. */
|
|
11
|
+
export type PartConfidence = "certain" | "fair" | "strong" | "weak";
|
|
12
|
+
/** How sure Maple is that this author is who the comment says. */
|
|
13
|
+
export type PartProvenance = "client" | "guest" | "server";
|
|
14
|
+
/** Everything a part may say about itself. Every field is optional. */
|
|
15
|
+
export interface PartState {
|
|
16
|
+
readonly status?: CommentStatus;
|
|
17
|
+
readonly form?: PartForm;
|
|
18
|
+
readonly confidence?: PartConfidence;
|
|
19
|
+
readonly provenance?: PartProvenance;
|
|
20
|
+
readonly armed?: boolean;
|
|
21
|
+
/** False for a comment still being written, which is drawn in grey. */
|
|
22
|
+
readonly sent?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** The rendered attributes, ready to spread. Absent state produces no attribute. */
|
|
25
|
+
export type PartAttributes = Readonly<Record<string, string>>;
|
|
26
|
+
/** Turns state into the six attributes. The only place their names appear. */
|
|
27
|
+
export declare function dataAttributes(state: PartState): PartAttributes;
|
|
28
|
+
/**
|
|
29
|
+
* What a pointer is doing to a part, rather than what its comment is.
|
|
30
|
+
*
|
|
31
|
+
* These are the overlay's own, so they carry the `mk` prefix the wire states
|
|
32
|
+
* do not: nothing here is recorded, sent, or true of the comment — a mark is
|
|
33
|
+
* peeked because a row is hovered, and nudged because someone moved it.
|
|
34
|
+
*/
|
|
35
|
+
export interface PointerState {
|
|
36
|
+
/** A row or the mark itself is under a pointer. Sticks to nothing. */
|
|
37
|
+
readonly peeked?: boolean;
|
|
38
|
+
/** Moved off what it was covering, and holding where it was put. */
|
|
39
|
+
readonly nudged?: boolean;
|
|
40
|
+
readonly dragging?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** The three attributes, ready to spread. Absent state produces no attribute. */
|
|
43
|
+
export declare function pointerAttributes(state: PointerState): PartAttributes;
|
|
44
|
+
/**
|
|
45
|
+
* Fill, edge and colour never compete: this decides fill alone. An unsent
|
|
46
|
+
* comment is an outline and so is an unpinned one, which never reached the
|
|
47
|
+
* page; their colour is what separates them from an open comment.
|
|
48
|
+
*/
|
|
49
|
+
export declare function formFor(status: CommentStatus | undefined, sent?: boolean): PartForm;
|
|
50
|
+
/** The four confidence words, at the thresholds the tooltips quote. */
|
|
51
|
+
export declare function confidenceFor(value: number): PartConfidence;
|
|
52
|
+
//#endregion
|
package/dist/data.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/data.ts
|
|
2
|
+
function dataAttributes(state) {
|
|
3
|
+
const attributes = {};
|
|
4
|
+
if (state.status) attributes["data-status"] = state.status;
|
|
5
|
+
if (state.form) attributes["data-form"] = state.form;
|
|
6
|
+
if (state.confidence) attributes["data-confidence"] = state.confidence;
|
|
7
|
+
if (state.provenance) attributes["data-provenance"] = state.provenance;
|
|
8
|
+
if (state.armed !== void 0) attributes["data-armed"] = String(state.armed);
|
|
9
|
+
if (state.sent !== void 0) attributes["data-sent"] = String(state.sent);
|
|
10
|
+
return attributes;
|
|
11
|
+
}
|
|
12
|
+
function pointerAttributes(state) {
|
|
13
|
+
const attributes = {};
|
|
14
|
+
if (state.peeked !== void 0) attributes["data-mk-peeked"] = String(state.peeked);
|
|
15
|
+
if (state.nudged !== void 0) attributes["data-mk-nudged"] = String(state.nudged);
|
|
16
|
+
if (state.dragging !== void 0) attributes["data-mk-dragging"] = String(state.dragging);
|
|
17
|
+
return attributes;
|
|
18
|
+
}
|
|
19
|
+
function formFor(status, sent = true) {
|
|
20
|
+
if (!sent) return "outline";
|
|
21
|
+
if (status === "resolved") return "solid";
|
|
22
|
+
return status === "needs_reverify" ? "partial" : "outline";
|
|
23
|
+
}
|
|
24
|
+
function confidenceFor(value) {
|
|
25
|
+
if (value >= .95) return "certain";
|
|
26
|
+
if (value >= .85) return "strong";
|
|
27
|
+
return value >= .65 ? "fair" : "weak";
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { confidenceFor, dataAttributes, formFor, pointerAttributes };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createIcon } from "./icon.js";
|
|
2
|
+
//#region src/icons/branch.ts
|
|
3
|
+
const BranchIcon = createIcon({
|
|
4
|
+
d: "M5 3.4v9.2 M6.6 2.6a1.6 1.6 0 1 1-3.2 0 1.6 1.6 0 1 1 3.2 0 M6.6 13.4a1.6 1.6 0 1 1-3.2 0 1.6 1.6 0 1 1 3.2 0 M12.6 4.6a1.6 1.6 0 1 1-3.2 0 1.6 1.6 0 1 1 3.2 0 M11 6.2c0 2.6-6 1.8-6 5",
|
|
5
|
+
strokeWidth: 1.3
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { BranchIcon };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createIcon } from "./icon.js";
|
|
2
|
+
//#region src/icons/cog.ts
|
|
3
|
+
const CogIcon = createIcon({
|
|
4
|
+
d: "M2.5 5.5h2.7 M8.8 5.5h4.7 M2.5 10.5h4.7 M10.8 10.5h2.7 M8.8 5.5a1.8 1.8 0 1 1-3.6 0 1.8 1.8 0 1 1 3.6 0 M10.8 10.5a1.8 1.8 0 1 1-3.6 0 1.8 1.8 0 1 1 3.6 0",
|
|
5
|
+
strokeWidth: 1.3
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { CogIcon };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from "react";
|
|
2
|
+
//#region src/icons/crossfade.d.ts
|
|
3
|
+
/** What a part hands the cross-fade: the icon, and what to call it. */
|
|
4
|
+
export interface IconCrossfadeProps {
|
|
5
|
+
/** Changing this starts a swap. Two icons with one name never cross-fade. */
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly children: ReactNode;
|
|
8
|
+
readonly className?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Derived state, set during render rather than in an effect: an effect would
|
|
12
|
+
* paint the new icon once at full opacity before the transition began.
|
|
13
|
+
*/
|
|
14
|
+
export declare function IconCrossfade(props: IconCrossfadeProps): ReactElement;
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createElement, useState } from "react";
|
|
2
|
+
//#region src/icons/crossfade.ts
|
|
3
|
+
function IconCrossfade(props) {
|
|
4
|
+
const next = {
|
|
5
|
+
name: props.name,
|
|
6
|
+
node: props.children
|
|
7
|
+
};
|
|
8
|
+
const [swap, setSwap] = useState({ current: next });
|
|
9
|
+
if (swap.current.name !== props.name) setSwap({
|
|
10
|
+
current: next,
|
|
11
|
+
previous: swap.current
|
|
12
|
+
});
|
|
13
|
+
const className = props.className ? `mk-icon-swap ${props.className}` : "mk-icon-swap";
|
|
14
|
+
const shown = swap.current.name === props.name ? swap.current : next;
|
|
15
|
+
return createElement("span", {
|
|
16
|
+
className,
|
|
17
|
+
onTransitionEnd: () => setSwap({ current: shown })
|
|
18
|
+
}, swap.previous ? frame(swap.previous, "out") : null, frame(shown, "in"));
|
|
19
|
+
}
|
|
20
|
+
function frame(shown, direction) {
|
|
21
|
+
return createElement("span", {
|
|
22
|
+
key: shown.name,
|
|
23
|
+
"data-mk-icon": direction
|
|
24
|
+
}, shown.node);
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { IconCrossfade };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ForwardRefExoticComponent, RefAttributes, SVGProps } from "react";
|
|
2
|
+
//#region src/icons/icon.d.ts
|
|
3
|
+
/** Icons are drawn at 13px unless a part asks for another size. */
|
|
4
|
+
export declare const ICON_SIZE = 13;
|
|
5
|
+
/** Anything an `<svg>` takes, plus the one size the parts vary. */
|
|
6
|
+
export interface IconProps extends Omit<SVGProps<SVGSVGElement>, "ref"> {
|
|
7
|
+
readonly size?: number;
|
|
8
|
+
}
|
|
9
|
+
/** What `createIcon` returns: a forwarding component, ref and className included. */
|
|
10
|
+
export type IconComponent = ForwardRefExoticComponent<IconProps & RefAttributes<SVGSVGElement>>;
|
|
11
|
+
/** The path, and the three things that vary between them. */
|
|
12
|
+
export interface IconSpec {
|
|
13
|
+
readonly d: string;
|
|
14
|
+
readonly strokeWidth?: number;
|
|
15
|
+
readonly dashArray?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Filled rather than stroked: a stroked glyph at 14px is three hairlines with
|
|
18
|
+
* gaps between them, and reads as an outline of nothing in particular.
|
|
19
|
+
*/
|
|
20
|
+
readonly filled?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Builds one icon. Called once per module, so a bundler can drop the unused. */
|
|
23
|
+
export declare function createIcon(spec: IconSpec): IconComponent;
|
|
24
|
+
//#endregion
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createElement, forwardRef } from "react";
|
|
2
|
+
//#region src/icons/icon.ts
|
|
3
|
+
const ICON_SIZE = 13;
|
|
4
|
+
function createIcon(spec) {
|
|
5
|
+
return forwardRef(function Icon(props, ref) {
|
|
6
|
+
const { size = 13, ...rest } = props;
|
|
7
|
+
return createElement("svg", {
|
|
8
|
+
"aria-hidden": true,
|
|
9
|
+
focusable: false,
|
|
10
|
+
...rest,
|
|
11
|
+
ref,
|
|
12
|
+
width: size,
|
|
13
|
+
height: size,
|
|
14
|
+
viewBox: "0 0 16 16",
|
|
15
|
+
fill: spec.filled === true ? "currentColor" : "none",
|
|
16
|
+
stroke: spec.filled === true ? "none" : "currentColor",
|
|
17
|
+
strokeWidth: spec.strokeWidth ?? 1.4,
|
|
18
|
+
strokeLinecap: "round",
|
|
19
|
+
strokeLinejoin: "round"
|
|
20
|
+
}, createElement("path", {
|
|
21
|
+
d: spec.d,
|
|
22
|
+
...spec.dashArray === void 0 ? {} : { strokeDasharray: spec.dashArray }
|
|
23
|
+
}));
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { ICON_SIZE, createIcon };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ICON_SIZE, IconComponent, IconProps, IconSpec, createIcon } from "./icon.js";
|
|
2
|
+
import { BranchIcon } from "./branch.js";
|
|
3
|
+
import { CogIcon } from "./cog.js";
|
|
4
|
+
import { CommitIcon } from "./commit.js";
|
|
5
|
+
import { IconCrossfade, IconCrossfadeProps } from "./crossfade.js";
|
|
6
|
+
import { ElementIcon } from "./element.js";
|
|
7
|
+
import { NoPlaceIcon } from "./noplace.js";
|
|
8
|
+
import { RegionIcon } from "./region.js";
|
|
9
|
+
import { SmileyIcon } from "./smiley.js";
|
|
10
|
+
import { SparkleIcon } from "./sparkle.js";
|
|
11
|
+
import { TargetIcon } from "./target.js";
|
|
12
|
+
import { TextIcon } from "./text.js";
|
|
13
|
+
export { BranchIcon, CogIcon, CommitIcon, ElementIcon, ICON_SIZE, type IconComponent, IconCrossfade, type IconCrossfadeProps, type IconProps, type IconSpec, NoPlaceIcon, RegionIcon, SmileyIcon, SparkleIcon, TargetIcon, TextIcon, createIcon };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ICON_SIZE, createIcon } from "./icon.js";
|
|
2
|
+
import { SparkleIcon } from "./sparkle.js";
|
|
3
|
+
import { SmileyIcon } from "./smiley.js";
|
|
4
|
+
import { IconCrossfade } from "./crossfade.js";
|
|
5
|
+
import { ElementIcon } from "./element.js";
|
|
6
|
+
import { RegionIcon } from "./region.js";
|
|
7
|
+
import { TextIcon } from "./text.js";
|
|
8
|
+
import { CogIcon } from "./cog.js";
|
|
9
|
+
import { BranchIcon } from "./branch.js";
|
|
10
|
+
import { CommitIcon } from "./commit.js";
|
|
11
|
+
import { NoPlaceIcon } from "./noplace.js";
|
|
12
|
+
import { TargetIcon } from "./target.js";
|
|
13
|
+
export { BranchIcon, CogIcon, CommitIcon, ElementIcon, ICON_SIZE, IconCrossfade, NoPlaceIcon, RegionIcon, SmileyIcon, SparkleIcon, TargetIcon, TextIcon, createIcon };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createIcon } from "./icon.js";
|
|
2
|
+
//#region src/icons/smiley.ts
|
|
3
|
+
const SmileyIcon = createIcon({
|
|
4
|
+
d: "M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1Zm0 1.5a5.5 5.5 0 1 1 0 11 5.5 5.5 0 0 1 0-11ZM5.9 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2Zm4.2 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2ZM4.9 9.4a.75.75 0 0 1 1 .3 2.45 2.45 0 0 0 4.2 0 .75.75 0 1 1 1.3.75 3.95 3.95 0 0 1-6.8 0 .75.75 0 0 1 .3-1.05Z",
|
|
5
|
+
filled: true
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { SmileyIcon };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createIcon } from "./icon.js";
|
|
2
|
+
//#region src/icons/sparkle.ts
|
|
3
|
+
const SparkleIcon = createIcon({
|
|
4
|
+
d: "M6.4 2.2 7.5 5.4 10.7 6.5 7.5 7.6 6.4 10.8 5.3 7.6 2.1 6.5 5.3 5.4Z M11.6 9.4 12.2 11 13.8 11.6 12.2 12.2 11.6 13.8 11 12.2 9.4 11.6 11 11Z",
|
|
5
|
+
strokeWidth: 1.1
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { SparkleIcon };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MOTION_TOKENS, RADIUS_TOKENS, REDUCED_MOTION_TOKENS, RUNTIME_TOKENS, SHEET_BREAKPOINT_PX } from "./tokens.js";
|
|
2
|
+
import { AsChildError, AsChildProps, Slot, SlotProps, composeRefs, mergeProps } from "./slot.js";
|
|
3
|
+
import { MapleUiContextError, MapleUiContextValue, useMapleUi } from "./context.js";
|
|
4
|
+
import { PartAttributes, PartConfidence, PartForm, PartProvenance, PartState, PointerState, confidenceFor, dataAttributes, formFor, pointerAttributes } from "./data.js";
|
|
5
|
+
import { DETAIL_COPY, ORPHAN_LABELS, ORPHAN_ORDER, ORPHAN_SENTENCES, PROVENANCE_SENTENCES, RUNG_LABELS, STATUS_LABELS, STATUS_SENTENCES, orphanTitle, rungLabel } from "./language.js";
|
|
6
|
+
import { MapleRoot, MapleRootProps, ThemePreference } from "./root.js";
|
|
7
|
+
import { REVIEWER_SLOT_COUNT, SLOT_INK_PROPERTY, SLOT_PROPERTY, applyReviewerSlot, slotColor, slotInk } from "./slots.js";
|
|
8
|
+
import { OVERLAY_CSS, SCHEME_ATTRIBUTE } from "./stylesheet.js";
|
|
9
|
+
import { OverlayTheme, useOverlayScheme } from "./theme.js";
|
|
10
|
+
import { Tip, TipProps, tipSpot } from "./tip.js";
|
|
11
|
+
export { AsChildError, type AsChildProps, DETAIL_COPY, MOTION_TOKENS, MapleRoot, type MapleRootProps, MapleUiContextError, type MapleUiContextValue, ORPHAN_LABELS, ORPHAN_ORDER, ORPHAN_SENTENCES, OVERLAY_CSS, type OverlayTheme, PROVENANCE_SENTENCES, type PartAttributes, type PartConfidence, type PartForm, type PartProvenance, type PartState, type PointerState, RADIUS_TOKENS, REDUCED_MOTION_TOKENS, REVIEWER_SLOT_COUNT, RUNG_LABELS, RUNTIME_TOKENS, MapleRoot as Root, SCHEME_ATTRIBUTE, SHEET_BREAKPOINT_PX, SLOT_INK_PROPERTY, SLOT_PROPERTY, STATUS_LABELS, STATUS_SENTENCES, Slot, type SlotProps, type ThemePreference, Tip, type TipProps, applyReviewerSlot, composeRefs, confidenceFor, dataAttributes, formFor, mergeProps, orphanTitle, pointerAttributes, rungLabel, slotColor, slotInk, tipSpot, useMapleUi, useOverlayScheme };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MapleUiContextError, useMapleUi } from "./context.js";
|
|
2
|
+
import { confidenceFor, dataAttributes, formFor, pointerAttributes } from "./data.js";
|
|
3
|
+
import { DETAIL_COPY, ORPHAN_LABELS, ORPHAN_ORDER, ORPHAN_SENTENCES, PROVENANCE_SENTENCES, RUNG_LABELS, STATUS_LABELS, STATUS_SENTENCES, orphanTitle, rungLabel } from "./language.js";
|
|
4
|
+
import { MOTION_TOKENS, RADIUS_TOKENS, REDUCED_MOTION_TOKENS, RUNTIME_TOKENS, SHEET_BREAKPOINT_PX } from "./tokens.js";
|
|
5
|
+
import { OVERLAY_CSS, SCHEME_ATTRIBUTE } from "./stylesheet.js";
|
|
6
|
+
import { useOverlayScheme } from "./theme.js";
|
|
7
|
+
import { MapleRoot } from "./root.js";
|
|
8
|
+
import { AsChildError, Slot, composeRefs, mergeProps } from "./slot.js";
|
|
9
|
+
import { REVIEWER_SLOT_COUNT, SLOT_INK_PROPERTY, SLOT_PROPERTY, applyReviewerSlot, slotColor, slotInk } from "./slots.js";
|
|
10
|
+
import { Tip, tipSpot } from "./tip.js";
|
|
11
|
+
export { AsChildError, DETAIL_COPY, MOTION_TOKENS, MapleRoot, MapleUiContextError, ORPHAN_LABELS, ORPHAN_ORDER, ORPHAN_SENTENCES, OVERLAY_CSS, PROVENANCE_SENTENCES, RADIUS_TOKENS, REDUCED_MOTION_TOKENS, REVIEWER_SLOT_COUNT, RUNG_LABELS, RUNTIME_TOKENS, MapleRoot as Root, SCHEME_ATTRIBUTE, SHEET_BREAKPOINT_PX, SLOT_INK_PROPERTY, SLOT_PROPERTY, STATUS_LABELS, STATUS_SENTENCES, Slot, Tip, applyReviewerSlot, composeRefs, confidenceFor, dataAttributes, formFor, mergeProps, orphanTitle, pointerAttributes, rungLabel, slotColor, slotInk, tipSpot, useMapleUi, useOverlayScheme };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PartProps } from "../part.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/island/account.d.ts
|
|
4
|
+
/** The row. Its children replace everything inside it. */
|
|
5
|
+
export interface AccountProps extends PartProps {
|
|
6
|
+
readonly children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/** The GitHub link, as one row of the settings panel. */
|
|
9
|
+
export declare const Account: import("react").ForwardRefExoticComponent<AccountProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { cx, renderPart } from "../part.js";
|
|
2
|
+
import { ACCOUNT_COPY } from "./language.js";
|
|
3
|
+
import { createElement, forwardRef } from "react";
|
|
4
|
+
import { useGitHubLink, useMapleClient } from "@maple-kit/react";
|
|
5
|
+
//#region src/island/account.ts
|
|
6
|
+
const Account = forwardRef(function Account(props, ref) {
|
|
7
|
+
const { asChild, children, className, ...rest } = props;
|
|
8
|
+
const link = useGitHubLink();
|
|
9
|
+
const client = useMapleClient();
|
|
10
|
+
if (link.state === "unsupported") return null;
|
|
11
|
+
return renderPart("div", asChild, {
|
|
12
|
+
...rest,
|
|
13
|
+
className: cx("mk-setting", className),
|
|
14
|
+
"data-mk-link": link.state,
|
|
15
|
+
ref
|
|
16
|
+
}, children ?? [createElement("span", { key: "said" }, createElement("span", { className: "mk-setting-name" }, ACCOUNT_COPY.name), createElement("span", { className: "mk-setting-hint" }, said(link)), code(link)), action(link, client)]);
|
|
17
|
+
});
|
|
18
|
+
function said(link) {
|
|
19
|
+
if (link.state === "linked") return ACCOUNT_COPY.linkedAs(login(link.login));
|
|
20
|
+
if (link.state === "linking") return ACCOUNT_COPY.linking;
|
|
21
|
+
if (link.state === "failed") return link.reason;
|
|
22
|
+
return ACCOUNT_COPY.unlinked;
|
|
23
|
+
}
|
|
24
|
+
function login(name) {
|
|
25
|
+
return name === void 0 ? void 0 : `@${name}`;
|
|
26
|
+
}
|
|
27
|
+
function code(link) {
|
|
28
|
+
if (link.state !== "linking") return null;
|
|
29
|
+
return createElement("span", {
|
|
30
|
+
key: "code",
|
|
31
|
+
className: "mk-acct-code"
|
|
32
|
+
}, createElement("code", null, link.userCode), createElement("a", {
|
|
33
|
+
href: link.verificationUri,
|
|
34
|
+
target: "_blank",
|
|
35
|
+
rel: "noreferrer noopener"
|
|
36
|
+
}, ACCOUNT_COPY.open));
|
|
37
|
+
}
|
|
38
|
+
function action(link, client) {
|
|
39
|
+
if (link.state === "linking") return null;
|
|
40
|
+
const linked = link.state === "linked";
|
|
41
|
+
const offer = link.state === "failed" ? ACCOUNT_COPY.retry : ACCOUNT_COPY.link;
|
|
42
|
+
const label = linked ? ACCOUNT_COPY.unlink : offer;
|
|
43
|
+
return createElement("button", {
|
|
44
|
+
key: "act",
|
|
45
|
+
type: "button",
|
|
46
|
+
className: "mk-acct-do",
|
|
47
|
+
...linked ? { title: ACCOUNT_COPY.unlinkHint } : {},
|
|
48
|
+
onClick: () => void (linked ? client.unlinkGitHub() : client.linkGitHub())
|
|
49
|
+
}, label);
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { Account };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CommentFilter } from "@maple-kit/core/client";
|
|
2
|
+
import { Anchor, OrphanReason, Resolution } from "@maple-kit/core/anchor";
|
|
3
|
+
import { Comment } from "@maple-kit/core";
|
|
4
|
+
//#region src/island/comments.d.ts
|
|
5
|
+
/** The count beside one filter's pill. */
|
|
6
|
+
export type FilterCounts = Readonly<Record<CommentFilter, number>>;
|
|
7
|
+
/** Each comment's place on the branch, oldest first, keyed by id. */
|
|
8
|
+
export declare function numbersFor(comments: readonly Comment[]): ReadonlyMap<string, number>;
|
|
9
|
+
/**
|
|
10
|
+
* The live count beside every pill. `All` subtracts the resolved ones while
|
|
11
|
+
* they are hidden, because the list under it does too.
|
|
12
|
+
*/
|
|
13
|
+
export declare function countsFor(comments: readonly Comment[], showResolved: boolean): FilterCounts;
|
|
14
|
+
/**
|
|
15
|
+
* Why this comment has no place on the page, asked of the page itself. An
|
|
16
|
+
* anchor that resolves again has no reason, and the row says nothing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function orphanReason(anchor: Anchor, root: ParentNode): OrphanReason | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* What the cascade says about every anchor, in one pass. In default detail
|
|
21
|
+
* only the unpinned are asked: nothing else on the row depends on the answer.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolutionsFor(comments: readonly Comment[], root: ParentNode, developer: boolean): ReadonlyMap<string, Resolution>;
|
|
24
|
+
//#endregion
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ORPHAN_ORDER } from "../language.js";
|
|
2
|
+
import { matchesFilter } from "@maple-kit/core/client";
|
|
3
|
+
import { resolveAnchor } from "@maple-kit/core/anchor";
|
|
4
|
+
//#region src/island/comments.ts
|
|
5
|
+
function numbersFor(comments) {
|
|
6
|
+
const ordered = [...comments].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
7
|
+
return new Map(ordered.map((comment, index) => [comment.id, index + 1]));
|
|
8
|
+
}
|
|
9
|
+
function countsFor(comments, showResolved) {
|
|
10
|
+
const count = (filter) => comments.filter((comment) => matchesFilter(comment, filter)).length;
|
|
11
|
+
const resolved = count("resolved");
|
|
12
|
+
return {
|
|
13
|
+
all: showResolved ? comments.length : comments.length - resolved,
|
|
14
|
+
open: count("open"),
|
|
15
|
+
needs_reverify: count("needs_reverify"),
|
|
16
|
+
resolved,
|
|
17
|
+
unpinned: count("unpinned")
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function orphanReason(anchor, root) {
|
|
21
|
+
const resolution = resolveAnchor(anchor, { root });
|
|
22
|
+
return resolution.status === "orphaned" ? resolution.reason : void 0;
|
|
23
|
+
}
|
|
24
|
+
function resolutionsFor(comments, root, developer) {
|
|
25
|
+
const found = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const comment of comments) {
|
|
27
|
+
if (!developer && comment.status !== "orphaned") continue;
|
|
28
|
+
found.set(comment.id, resolveAnchor(comment.anchor, { root }));
|
|
29
|
+
}
|
|
30
|
+
return found;
|
|
31
|
+
}
|
|
32
|
+
function byReason(comments, reasonOf) {
|
|
33
|
+
const rank = (comment) => {
|
|
34
|
+
const reason = reasonOf(comment);
|
|
35
|
+
return reason === void 0 ? ORPHAN_ORDER.length : ORPHAN_ORDER.indexOf(reason);
|
|
36
|
+
};
|
|
37
|
+
return [...comments].sort((a, b) => rank(a) - rank(b));
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { byReason, countsFor, numbersFor, orphanReason, resolutionsFor };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PartProps } from "../part.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/island/content.d.ts
|
|
4
|
+
/** The card. Everything the island shows when it is open goes inside it. */
|
|
5
|
+
export interface IslandContentProps extends PartProps {
|
|
6
|
+
readonly children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/** Mounted while the island is open, and through its exit. */
|
|
9
|
+
export declare const IslandContent: import("react").ForwardRefExoticComponent<IslandContentProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cx, renderPart } from "../part.js";
|
|
2
|
+
import { ISLAND_COPY } from "./language.js";
|
|
3
|
+
import { useIsland } from "./context.js";
|
|
4
|
+
import { forwardRef } from "react";
|
|
5
|
+
//#region src/island/content.ts
|
|
6
|
+
const PART = "<Maple.IslandContent>";
|
|
7
|
+
const IslandContent = forwardRef(function IslandContent(props, ref) {
|
|
8
|
+
const { asChild, children, className, ...rest } = props;
|
|
9
|
+
const island = useIsland(PART);
|
|
10
|
+
if (island.phase === "closed") return null;
|
|
11
|
+
const onAnimationEnd = (event) => {
|
|
12
|
+
if (island.phase === "closing" && event.target === event.currentTarget) island.settled();
|
|
13
|
+
};
|
|
14
|
+
return renderPart("div", asChild, {
|
|
15
|
+
role: "region",
|
|
16
|
+
...rest,
|
|
17
|
+
id: island.contentId,
|
|
18
|
+
"aria-label": ISLAND_COPY.title,
|
|
19
|
+
"data-mk-phase": island.phase,
|
|
20
|
+
className: cx("mk-card mk-surface", className),
|
|
21
|
+
onAnimationEnd,
|
|
22
|
+
ref
|
|
23
|
+
}, children);
|
|
24
|
+
});
|
|
25
|
+
//#endregion
|
|
26
|
+
export { IslandContent };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { OrphanReason, Resolution } from "@maple-kit/core/anchor";
|
|
2
|
+
import { Comment } from "@maple-kit/core";
|
|
3
|
+
//#region src/island/context.d.ts
|
|
4
|
+
/** Open, shut, or on its way out: a close animates before it unmounts. */
|
|
5
|
+
export type IslandPhase = "closed" | "closing" | "open";
|
|
6
|
+
/** What every part below `Maple.Island` reads. */
|
|
7
|
+
export interface IslandContextValue {
|
|
8
|
+
readonly phase: IslandPhase;
|
|
9
|
+
/** Opening is immediate; closing runs the exit and then unmounts. */
|
|
10
|
+
readonly setOpen: (open: boolean) => void;
|
|
11
|
+
/** Called by the card once its exit animation has finished. */
|
|
12
|
+
readonly settled: () => void;
|
|
13
|
+
/** Off by default. What it reveals is the developer detail, not the switch. */
|
|
14
|
+
readonly developer: boolean;
|
|
15
|
+
readonly setDeveloper: (on: boolean) => void;
|
|
16
|
+
/** The settings panel's, held here so Escape can shut the newest surface. */
|
|
17
|
+
readonly settingsOpen: boolean;
|
|
18
|
+
readonly setSettingsOpen: (open: boolean) => void;
|
|
19
|
+
/** Ties the pill to the card for assistive technology. */
|
|
20
|
+
readonly contentId: string;
|
|
21
|
+
/** Each comment's place on the branch, oldest first. */
|
|
22
|
+
readonly numbers: ReadonlyMap<string, number>;
|
|
23
|
+
/** Everything on the branch, whatever the filter says. */
|
|
24
|
+
readonly comments: readonly Comment[];
|
|
25
|
+
/** What the cascade says about each anchor, asked of the page as it is now. */
|
|
26
|
+
readonly resolutions: ReadonlyMap<string, Resolution>;
|
|
27
|
+
/** The comment a link or a mark asked to be looked at, for the row to mark. */
|
|
28
|
+
readonly selected: string | null;
|
|
29
|
+
/** Drag state, so the pill moves the island and the card stays where it is. */
|
|
30
|
+
readonly drag: DragHandlers;
|
|
31
|
+
}
|
|
32
|
+
/** What the pill spreads to become the island's handle. */
|
|
33
|
+
export interface DragHandlers {
|
|
34
|
+
/** A ref callback for the island itself, which is the thing that moves. */
|
|
35
|
+
readonly attach: (node: HTMLElement | null) => void;
|
|
36
|
+
readonly onPointerDown: (event: PointerEventLike) => void;
|
|
37
|
+
readonly onPointerMove: (event: PointerEventLike) => void;
|
|
38
|
+
readonly onPointerUp: (event: PointerEventLike) => void;
|
|
39
|
+
/** True once the pointer travelled far enough to be a drag, not a click. */
|
|
40
|
+
readonly moved: () => boolean;
|
|
41
|
+
}
|
|
42
|
+
/** The parts of a pointer event a drag needs. Structural, so it tests flat. */
|
|
43
|
+
export interface PointerEventLike {
|
|
44
|
+
readonly clientX: number;
|
|
45
|
+
readonly clientY: number;
|
|
46
|
+
readonly pointerId: number;
|
|
47
|
+
readonly currentTarget: EventTarget | null;
|
|
48
|
+
}
|
|
49
|
+
/** Why this comment has no place, out of what the cascade answered. */
|
|
50
|
+
export declare function reasonOf(resolutions: ReadonlyMap<string, Resolution>, id: string): OrphanReason | undefined;
|
|
51
|
+
/** Thrown by an island part rendered outside `<Maple.Island>`. */
|
|
52
|
+
export declare class IslandContextError extends Error {
|
|
53
|
+
readonly name = "IslandContextError";
|
|
54
|
+
constructor(part: string);
|
|
55
|
+
}
|
|
56
|
+
/** The island's state, or a readable error rather than a null. */
|
|
57
|
+
export declare function useIsland(part: string): IslandContextValue;
|
|
58
|
+
//#endregion
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
//#region src/island/context.ts
|
|
3
|
+
function reasonOf(resolutions, id) {
|
|
4
|
+
const resolution = resolutions.get(id);
|
|
5
|
+
return resolution?.status === "orphaned" ? resolution.reason : void 0;
|
|
6
|
+
}
|
|
7
|
+
const IslandContext = createContext(null);
|
|
8
|
+
function listId(contentId) {
|
|
9
|
+
return `${contentId}-list`;
|
|
10
|
+
}
|
|
11
|
+
var IslandContextError = class extends Error {
|
|
12
|
+
name = "IslandContextError";
|
|
13
|
+
constructor(part) {
|
|
14
|
+
super(`${part} was rendered outside <Maple.Island>. Every island part needs one above it.`);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function useIsland(part) {
|
|
18
|
+
const value = useContext(IslandContext);
|
|
19
|
+
if (value === null) throw new IslandContextError(part);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { IslandContext, IslandContextError, listId, reasonOf, useIsland };
|