@agimon-ai/po-native-components 0.0.0-alpha.22 → 0.0.0-alpha.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AgentAvatar.d.mts +14 -0
- package/dist/components/AgentAvatar.d.mts.map +1 -0
- package/dist/components/AgentAvatar.mjs +87 -0
- package/dist/components/AgentAvatar.mjs.map +1 -0
- package/dist/components/Badge.d.mts +1 -1
- package/dist/components/Badge.mjs +1 -1
- package/dist/components/Button.mjs +1 -1
- package/dist/components/CodeBlock.d.mts.map +1 -1
- package/dist/components/CodeBlock.mjs +5 -34
- package/dist/components/CodeBlock.mjs.map +1 -1
- package/dist/components/CopyButton.d.mts +13 -0
- package/dist/components/CopyButton.d.mts.map +1 -0
- package/dist/components/CopyButton.mjs +43 -0
- package/dist/components/CopyButton.mjs.map +1 -0
- package/dist/components/Dialog.mjs +3 -3
- package/dist/components/Dot.d.mts +1 -1
- package/dist/components/Dot.mjs +2 -2
- package/dist/components/DropdownMenu.mjs +1 -1
- package/dist/components/HashlineLines.d.mts +13 -0
- package/dist/components/HashlineLines.d.mts.map +1 -0
- package/dist/components/HashlineLines.mjs +137 -0
- package/dist/components/HashlineLines.mjs.map +1 -0
- package/dist/components/Input.mjs +1 -1
- package/dist/components/Label.mjs +1 -1
- package/dist/components/List.mjs +1 -1
- package/dist/components/Markdown.d.mts +8 -1
- package/dist/components/Markdown.d.mts.map +1 -1
- package/dist/components/Markdown.mjs +199 -18
- package/dist/components/Markdown.mjs.map +1 -1
- package/dist/components/MessageItem.mjs +1 -1
- package/dist/components/SectionLabel.mjs +1 -1
- package/dist/components/Sheet.mjs +1 -1
- package/dist/components/SheetFrame.mjs +1 -1
- package/dist/components/Spinner.d.mts +1 -1
- package/dist/components/StatusBadge.d.mts +1 -1
- package/dist/components/SyntaxLine.d.mts +19 -0
- package/dist/components/SyntaxLine.d.mts.map +1 -0
- package/dist/components/SyntaxLine.mjs +132 -0
- package/dist/components/SyntaxLine.mjs.map +1 -0
- package/dist/components/Tabs.mjs +1 -1
- package/dist/components/ToolPathLink.d.mts +10 -0
- package/dist/components/ToolPathLink.d.mts.map +1 -0
- package/dist/components/ToolPathLink.mjs +40 -0
- package/dist/components/ToolPathLink.mjs.map +1 -0
- package/dist/icons/iconGlyphs.d.mts +16 -0
- package/dist/icons/iconGlyphs.d.mts.map +1 -1
- package/dist/icons/iconGlyphs.mjs +16 -0
- package/dist/icons/iconGlyphs.mjs.map +1 -1
- package/dist/icons/icons.d.mts +17 -1
- package/dist/icons/icons.d.mts.map +1 -1
- package/dist/icons/icons.mjs +5 -1
- package/dist/icons/icons.mjs.map +1 -1
- package/dist/index.d.mts +9 -4
- package/dist/index.mjs +9 -4
- package/dist/lib/markdown.mjs +101 -5
- package/dist/lib/markdown.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/components/AgentAvatar.d.ts
|
|
2
|
+
/** How an agent is doing, as the avatar's corner dot shows it. */
|
|
3
|
+
export type AgentState = 'running' | 'waiting' | 'done' | 'failed';
|
|
4
|
+
/** One letter for a first name, two for a hyphenated agent name (`po-developer` is PD). */
|
|
5
|
+
export declare function agentInitials(name: string): string;
|
|
6
|
+
/** An agent's face: its initials on a tint fixed by `seed`, with its state as a corner dot. */
|
|
7
|
+
export declare function AgentAvatar({ name, seed, state, size }: {
|
|
8
|
+
name: string;
|
|
9
|
+
seed?: string;
|
|
10
|
+
state?: AgentState;
|
|
11
|
+
size?: 'sm' | 'md';
|
|
12
|
+
}): import("react").JSX.Element;
|
|
13
|
+
//#endregion
|
|
14
|
+
//# sourceMappingURL=AgentAvatar.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentAvatar.d.mts","names":[],"sources":["../../src/components/AgentAvatar.tsx"],"mappings":";;YAQY;;wBAGI,cAAc;;wBA6Bd,cACd,MACA,MACA,OACA;EAEA;EACA;EACA,QAAQ;EACR;oBACD,IAAA"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { fontOf } from "../lib/fonts.mjs";
|
|
2
|
+
import { Dot } from "./Dot.mjs";
|
|
3
|
+
import { View } from "react-native-unistyles/components/native/View";
|
|
4
|
+
import { Text } from "react-native-unistyles/components/native/Text";
|
|
5
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/components/AgentAvatar.tsx
|
|
9
|
+
/** One letter for a first name, two for a hyphenated agent name (`po-developer` is PD). */
|
|
10
|
+
function agentInitials(name) {
|
|
11
|
+
return name.split(/[-_.\s]+/u).filter(Boolean).slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join("");
|
|
12
|
+
}
|
|
13
|
+
const TINTS = [
|
|
14
|
+
"green",
|
|
15
|
+
"teal",
|
|
16
|
+
"blue",
|
|
17
|
+
"cyan",
|
|
18
|
+
"yellow",
|
|
19
|
+
"violet"
|
|
20
|
+
];
|
|
21
|
+
function tintFor(seed) {
|
|
22
|
+
let hash = 0;
|
|
23
|
+
for (const char of seed) hash = (hash * 31 + char.charCodeAt(0)) % 997;
|
|
24
|
+
return TINTS[hash % TINTS.length] ?? "green";
|
|
25
|
+
}
|
|
26
|
+
const RING = 2;
|
|
27
|
+
const STATE_DOT = {
|
|
28
|
+
running: "green",
|
|
29
|
+
waiting: "yellow",
|
|
30
|
+
done: "neutral",
|
|
31
|
+
failed: "red"
|
|
32
|
+
};
|
|
33
|
+
/** An agent's face: its initials on a tint fixed by `seed`, with its state as a corner dot. */
|
|
34
|
+
function AgentAvatar({ name, seed = name, state, size = "md" }) {
|
|
35
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
36
|
+
accessible: true,
|
|
37
|
+
accessibilityRole: "image",
|
|
38
|
+
accessibilityLabel: state ? `${name}, ${state}` : name,
|
|
39
|
+
testID: "agent-avatar",
|
|
40
|
+
style: styles.frame,
|
|
41
|
+
children: [/* @__PURE__ */ jsx(View, {
|
|
42
|
+
style: styles.face(tintFor(seed), size === "sm" ? 24 : 32),
|
|
43
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
44
|
+
style: styles.initials,
|
|
45
|
+
children: agentInitials(name)
|
|
46
|
+
})
|
|
47
|
+
}), state ? /* @__PURE__ */ jsx(Dot, {
|
|
48
|
+
tone: STATE_DOT[state],
|
|
49
|
+
size: "md",
|
|
50
|
+
pulse: state === "running",
|
|
51
|
+
style: styles.dot
|
|
52
|
+
}) : null]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const styles = StyleSheet.create((theme) => ({
|
|
56
|
+
frame: { flexShrink: 0 },
|
|
57
|
+
face: (tint, side) => ({
|
|
58
|
+
width: side,
|
|
59
|
+
height: side,
|
|
60
|
+
alignItems: "center",
|
|
61
|
+
justifyContent: "center",
|
|
62
|
+
borderRadius: theme.borderRadius.full,
|
|
63
|
+
backgroundColor: theme.colors[`tint-${tint}`],
|
|
64
|
+
uni__dependencies: [0]
|
|
65
|
+
}),
|
|
66
|
+
initials: {
|
|
67
|
+
fontFamily: fontOf(theme.fontFamily.sans),
|
|
68
|
+
fontSize: theme.fontSize.sm,
|
|
69
|
+
lineHeight: theme.lineHeight.sm,
|
|
70
|
+
color: theme.colors.hi,
|
|
71
|
+
uni__dependencies: [0]
|
|
72
|
+
},
|
|
73
|
+
dot: {
|
|
74
|
+
position: "absolute",
|
|
75
|
+
right: -4,
|
|
76
|
+
bottom: -4,
|
|
77
|
+
width: theme.spacing(2) + 4,
|
|
78
|
+
height: theme.spacing(2) + 4,
|
|
79
|
+
borderWidth: RING,
|
|
80
|
+
borderColor: theme.colors.panel,
|
|
81
|
+
uni__dependencies: [0]
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
export { AgentAvatar, agentInitials };
|
|
87
|
+
//# sourceMappingURL=AgentAvatar.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentAvatar.mjs","names":["DotTone","StyleSheet","fontOf","Dot","AgentState","agentInitials","name","split","filter","Boolean","slice","map","part","charAt","toUpperCase","join","TINTS","const","Tint","tintFor","seed","hash","char","charCodeAt","length","RING","STATE_DOT","Readonly","Record","running","waiting","done","failed","AgentAvatar","state","size","styles","frame","face","initials","dot","create","theme","flexShrink","tint","side","width","height","alignItems","justifyContent","borderRadius","full","backgroundColor","colors","uni__dependencies","fontFamily","sans","fontSize","sm","lineHeight","color","hi","position","right","bottom","spacing","borderWidth","borderColor","panel"],"sources":["../../src/components/AgentAvatar.tsx"],"sourcesContent":["import type { DotTone } from '@agimon-ai/po-web-components/nativeTheme';\nimport { Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport { fontOf } from '../lib/fonts';\nimport { Dot } from './Dot';\n\n/** How an agent is doing, as the avatar's corner dot shows it. */\nexport type AgentState = 'running' | 'waiting' | 'done' | 'failed';\n\n/** One letter for a first name, two for a hyphenated agent name (`po-developer` is PD). */\nexport function agentInitials(name: string): string {\n return name\n .split(/[-_.\\s]+/u)\n .filter(Boolean)\n .slice(0, 2)\n .map((part) => part.charAt(0).toUpperCase())\n .join('');\n}\n\n// ponytail: mirrors po-web-components AgentAvatar's tint hash; keep the two in step so a seed reads the same tint.\nconst TINTS = ['green', 'teal', 'blue', 'cyan', 'yellow', 'violet'] as const;\ntype Tint = (typeof TINTS)[number];\n\nfunction tintFor(seed: string): Tint {\n let hash = 0;\n for (const char of seed) hash = (hash * 31 + char.charCodeAt(0)) % 997;\n return TINTS[hash % TINTS.length] ?? 'green';\n}\n\nconst RING = 2;\n\nconst STATE_DOT: Readonly<Record<AgentState, DotTone>> = {\n running: 'green',\n waiting: 'yellow',\n done: 'neutral',\n failed: 'red',\n};\n\n/** An agent's face: its initials on a tint fixed by `seed`, with its state as a corner dot. */\nexport function AgentAvatar({\n name,\n seed = name,\n state,\n size = 'md',\n}: {\n name: string;\n seed?: string;\n state?: AgentState;\n size?: 'sm' | 'md';\n}) {\n return (\n <View\n accessible\n accessibilityRole=\"image\"\n accessibilityLabel={state ? `${name}, ${state}` : name}\n testID=\"agent-avatar\"\n style={styles.frame}\n >\n <View style={styles.face(tintFor(seed), size === 'sm' ? 24 : 32)}>\n <Text style={styles.initials}>{agentInitials(name)}</Text>\n </View>\n {state ? <Dot tone={STATE_DOT[state]} size=\"md\" pulse={state === 'running'} style={styles.dot} /> : null}\n </View>\n );\n}\n\nconst styles = StyleSheet.create((theme) => ({\n frame: { flexShrink: 0 },\n // `size-6` and `size-8`.\n face: (tint: Tint, side: number) => ({\n width: side,\n height: side,\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: theme.borderRadius.full,\n backgroundColor: theme.colors[`tint-${tint}`],\n }),\n initials: {\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n color: theme.colors.hi,\n },\n // `-right-0.5 -bottom-0.5 ring-2 ring-po-panel`: a ring sits outside the dot, a border inside, so the box grows by it.\n dot: {\n position: 'absolute',\n right: -2 - RING,\n bottom: -2 - RING,\n width: theme.spacing(2) + 2 * RING,\n height: theme.spacing(2) + 2 * RING,\n borderWidth: RING,\n borderColor: theme.colors.panel,\n },\n}));\n"],"mappings":";;;;;;;;;AAWA,SAAgBK,cAAcC,MAAsB;CAClD,OAAOA,KACJC,MAAM,WAAW,CAAC,CAClBC,OAAOC,OAAO,CAAC,CACfC,MAAM,GAAG,CAAC,CAAC,CACXC,KAAKC,SAASA,KAAKC,OAAO,CAAC,CAAC,CAACC,YAAY,CAAC,CAAC,CAC3CC,KAAK,EAAE;AACZ;AAGA,MAAMC,QAAQ;CAAC;CAAS;CAAQ;CAAQ;CAAQ;CAAU;AAAQ;AAGlE,SAASG,QAAQC,MAAoB;CACnC,IAAIC,OAAO;CACX,KAAK,MAAMC,QAAQF,MAAMC,QAAQA,OAAO,KAAKC,KAAKC,WAAW,CAAC,KAAK;CACnE,OAAOP,MAAMK,OAAOL,MAAMQ,WAAW;AACvC;AAEA,MAAMC,OAAO;AAEb,MAAMC,YAAmD;CACvDG,SAAS;CACTC,SAAS;CACTC,MAAM;CACNC,QAAQ;AACV;;AAGA,SAAgBC,YAAY,EAC1B3B,MACAc,OAAOd,MACP4B,OACAC,OAAO,QAMN;CACD,OACE,qBAAC,MAAD;EACE;EACA,mBAAkB;EAClB,oBAAoBD,QAAQ,GAAG5B,KAAI,IAAK4B,UAAU5B;EAClD,QAAO;EACP,OAAO8B,OAAOC;YALhB,CAOE,oBAAC,MAAD;GAAM,OAAOD,OAAOE,KAAKnB,QAAQC,IAAI,GAAGe,SAAS,OAAO,KAAK,EAAE;aAC7D,oBAAC,MAAD;IAAM,OAAOC,OAAOG;cAAWlC,cAAcC,IAAI;GAAQ;EACrD,IACL4B,QAAQ,oBAAC,KAAD;GAAK,MAAMR,UAAUQ;GAAQ,MAAK;GAAK,OAAOA,UAAU;GAAW,OAAOE,OAAOI;EAAI,KAAM,IAChG;;AAEV;AAEA,MAAMJ,SAASnC,WAAWwC,QAAQC,WAAW;CAC3CL,OAAO,EAAEM,YAAY,EAAE;CAEvBL,OAAOM,MAAYC,UAAkB;EACnCC,OAAOD;EACPE,QAAQF;EACRG,YAAY;EACZC,gBAAgB;EAChBC,cAAcR,MAAMQ,aAAaC;EACjCC,iBAAiBV,MAAMW,OAAO,QAAQT;EAAOU,mBAAA,CAAA,CAAA;CAC/C;CACAf,UAAU;EACRgB,YAAYrD,OAAOwC,MAAMa,WAAWC,IAAI;EACxCC,UAAUf,MAAMe,SAASC;EACzBC,YAAYjB,MAAMiB,WAAWD;EAC7BE,OAAOlB,MAAMW,OAAOQ;EAAEP,mBAAA,CAAA,CAAA;CACxB;CAEAd,KAAK;EACHsB,UAAU;EACVC,OAAO;EACPC,QAAQ;EACRlB,OAAOJ,MAAMuB,QAAQ,CAAC,IAAI;EAC1BlB,QAAQL,MAAMuB,QAAQ,CAAC,IAAI;EAC3BC,aAAazC;EACb0C,aAAazB,MAAMW,OAAOe;EAAKd,mBAAA,CAAA,CAAA;CACjC;AACF,EAAE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ChipTone } from "@agimon-ai/po-web-components/nativeTheme";
|
|
2
1
|
import { StyleProp, ViewProps, ViewStyle } from "react-native";
|
|
2
|
+
import { ChipTone } from "@agimon-ai/po-web-components/nativeTheme";
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
4
|
//#region src/components/Badge.d.ts
|
|
5
5
|
export type BadgeTone = ChipTone;
|
|
@@ -2,8 +2,8 @@ import { fontOf } from "../lib/fonts.mjs";
|
|
|
2
2
|
import { CHIP_INK } from "../lib/tone.mjs";
|
|
3
3
|
import { wrapText } from "../lib/wrapText.mjs";
|
|
4
4
|
import { View } from "react-native-unistyles/components/native/View";
|
|
5
|
-
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
6
5
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
6
|
+
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
8
|
|
|
9
9
|
//#region src/components/Badge.tsx
|
|
@@ -3,8 +3,8 @@ import { wrapText } from "../lib/wrapText.mjs";
|
|
|
3
3
|
import { IconColorContext } from "../icons/IconColorContext.mjs";
|
|
4
4
|
import { impactLight } from "../lib/haptics.mjs";
|
|
5
5
|
import { Spinner } from "./Spinner.mjs";
|
|
6
|
-
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
7
6
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
7
|
+
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { Pressable } from "react-native-unistyles/components/native/Pressable";
|
|
10
10
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlock.d.mts","names":[],"sources":["../../src/components/CodeBlock.tsx"],"mappings":";
|
|
1
|
+
{"version":3,"file":"CodeBlock.d.mts","names":[],"sources":["../../src/components/CodeBlock.tsx"],"mappings":";iBAciB;;EAEf;;EAEA;;wBAGc,YAAY,MAAM,YAAY,iCAAc,IAAA"}
|
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
import { fontOf } from "../lib/fonts.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { CheckIcon, CopyIcon } from "../icons/icons.mjs";
|
|
2
|
+
import { CopyButton } from "./CopyButton.mjs";
|
|
4
3
|
import { View } from "react-native-unistyles/components/native/View";
|
|
5
|
-
import { StyleSheet } from "react-native-unistyles";
|
|
6
4
|
import { Text } from "react-native-unistyles/components/native/Text";
|
|
7
|
-
import {
|
|
5
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
8
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
7
|
import { ScrollView } from "react-native-unistyles/components/native/ScrollView";
|
|
10
|
-
import { setStringAsync } from "expo-clipboard";
|
|
11
8
|
|
|
12
9
|
//#region src/components/CodeBlock.tsx
|
|
13
|
-
/** How long the control stays acknowledged before returning to its icon. */
|
|
14
|
-
const FEEDBACK_MS = 1500;
|
|
15
|
-
const LABELS = {
|
|
16
|
-
idle: "copy",
|
|
17
|
-
copied: "copied",
|
|
18
|
-
failed: "copying failed"
|
|
19
|
-
};
|
|
20
10
|
function CodeBlock({ text, language }) {
|
|
21
|
-
const [state, setState] = useState("idle");
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (state === "idle") return void 0;
|
|
24
|
-
const timer = setTimeout(() => setState("idle"), FEEDBACK_MS);
|
|
25
|
-
return () => clearTimeout(timer);
|
|
26
|
-
}, [state]);
|
|
27
|
-
const label = LABELS[state];
|
|
28
11
|
return /* @__PURE__ */ jsxs(View, {
|
|
29
12
|
style: styles.block,
|
|
30
13
|
accessibilityLabel: language === void 0 ? void 0 : `${language} code`,
|
|
@@ -37,21 +20,9 @@ function CodeBlock({ text, language }) {
|
|
|
37
20
|
style: styles.code,
|
|
38
21
|
children: text
|
|
39
22
|
})
|
|
40
|
-
}), /* @__PURE__ */ jsx(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
accessibilityLabel: label,
|
|
44
|
-
onPress: () => {
|
|
45
|
-
setStringAsync(text).then((saved) => setState(saved ? "copied" : "failed"), () => setState("failed"));
|
|
46
|
-
},
|
|
47
|
-
style: styles.copy,
|
|
48
|
-
children: state === "copied" ? /* @__PURE__ */ jsx(CheckIcon, {
|
|
49
|
-
size: 12,
|
|
50
|
-
color: "green"
|
|
51
|
-
}) : /* @__PURE__ */ jsx(CopyIcon, {
|
|
52
|
-
size: 12,
|
|
53
|
-
color: "faint"
|
|
54
|
-
})
|
|
23
|
+
}), /* @__PURE__ */ jsx(CopyButton, {
|
|
24
|
+
text,
|
|
25
|
+
style: styles.copy
|
|
55
26
|
})]
|
|
56
27
|
});
|
|
57
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlock.mjs","names":["
|
|
1
|
+
{"version":3,"file":"CodeBlock.mjs","names":["StyleSheet","fontOf","CopyButton","CodeBlockProps","text","language","CodeBlock","styles","block","undefined","scroll","code","copy","create","theme","borderRadius","DEFAULT","borderWidth","borderColor","colors","border","backgroundColor","deep","uni__dependencies","padding","spacing","paddingRight","color","fontFamily","mono","fontSize","sm","lineHeight","lineHeightRelaxed","position","top","right"],"sources":["../../src/components/CodeBlock.tsx"],"sourcesContent":["import { ScrollView, Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport { fontOf } from '../lib/fonts';\nimport { CopyButton } from './CopyButton';\n\n/*\n * A fenced code block: the source in selectable mono type that scrolls\n * sideways rather than wrapping, and a copy button that says when it worked.\n *\n * ponytail: no syntax colouring and no mermaid diagrams yet; a mermaid fence\n * shows its source, which is still the whole content.\n */\n\nexport interface CodeBlockProps {\n /** The block's source, without the fence lines. */\n text: string;\n /** The fence's language word, such as `ts`; the web reads it from a `language-*` class. */\n language?: string;\n}\n\nexport function CodeBlock({ text, language }: CodeBlockProps) {\n return (\n <View style={styles.block} accessibilityLabel={language === undefined ? undefined : `${language} code`}>\n <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.scroll}>\n <Text selectable style={styles.code}>\n {text}\n </Text>\n </ScrollView>\n <CopyButton text={text} style={styles.copy} />\n </View>\n );\n}\n\nconst styles = StyleSheet.create((theme) => ({\n block: {\n borderRadius: theme.borderRadius.DEFAULT,\n borderWidth: 1,\n borderColor: theme.colors.border,\n backgroundColor: theme.colors.deep,\n },\n // The right padding keeps the first line clear of the copy button.\n scroll: { padding: theme.spacing(2.5), paddingRight: theme.spacing(9) },\n code: {\n color: theme.colors.text,\n fontFamily: fontOf(theme.fontFamily.mono),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeightRelaxed.sm,\n },\n copy: { position: 'absolute', top: theme.spacing(1.5), right: theme.spacing(1.5) },\n}));\n"],"mappings":";;;;;;;;;AAqBA,SAAgBM,UAAU,EAAEF,MAAMC,YAA4B;CAC5D,OACE,qBAAC,MAAD;EAAM,OAAOE,OAAOC;EAAO,oBAAoBH,aAAaI,SAAYA,SAAY,GAAGJ,SAAQ;YAA/F,CACE,oBAAC,YAAD;GAAY;GAAW,gCAAgC;GAAO,uBAAuBE,OAAOG;aAC1F,oBAAC,MAAD;IAAM;IAAW,OAAOH,OAAOI;cAC5BP;GACG;EACI,IACZ,oBAAC,YAAD;GAAkBA;GAAM,OAAOG,OAAOK;EAAK,EACvC;;AAEV;AAEA,MAAML,SAASP,WAAWa,QAAQC,WAAW;CAC3CN,OAAO;EACLO,cAAcD,MAAMC,aAAaC;EACjCC,aAAa;EACbC,aAAaJ,MAAMK,OAAOC;EAC1BC,iBAAiBP,MAAMK,OAAOG;EAAIC,mBAAA,CAAA,CAAA;CACpC;CAEAb,QAAQ;EAAEc,SAASV,MAAMW,QAAQ,GAAG;EAAGC,cAAcZ,MAAMW,QAAQ,CAAC;EAACF,mBAAA,CAAA,CAAA;CAAC;CACtEZ,MAAM;EACJgB,OAAOb,MAAMK,OAAOf;EACpBwB,YAAY3B,OAAOa,MAAMc,WAAWC,IAAI;EACxCC,UAAUhB,MAAMgB,SAASC;EACzBC,YAAYlB,MAAMmB,kBAAkBF;EAAER,mBAAA,CAAA,CAAA;CACxC;CACAX,MAAM;EAAEsB,UAAU;EAAYC,KAAKrB,MAAMW,QAAQ,GAAG;EAAGW,OAAOtB,MAAMW,QAAQ,GAAG;EAACF,mBAAA,CAAA,CAAA;CAAC;AACnF,EAAE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StyleProp, ViewStyle } from "react-native";
|
|
2
|
+
//#region src/components/CopyButton.d.ts
|
|
3
|
+
export interface CopyButtonProps {
|
|
4
|
+
/** The text the press puts on the clipboard. */
|
|
5
|
+
text: string;
|
|
6
|
+
/** What is copied, announced before the state, such as `path`. */
|
|
7
|
+
label?: string;
|
|
8
|
+
style?: StyleProp<ViewStyle>;
|
|
9
|
+
}
|
|
10
|
+
/** A quiet icon button that copies text and says, briefly, whether it worked. */
|
|
11
|
+
export declare function CopyButton({ text, label, style }: CopyButtonProps): import("react").JSX.Element;
|
|
12
|
+
//#endregion
|
|
13
|
+
//# sourceMappingURL=CopyButton.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopyButton.d.mts","names":[],"sources":["../../src/components/CopyButton.tsx"],"mappings":";;iBAkBiB;;EAEf;;EAEA;EACA,QAAQ,UAAU;;;wBAIJ,aAAa,MAAM,OAAO,SAAS,kCAAe,IAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Button } from "./Button.mjs";
|
|
2
|
+
import { CheckIcon, CopyIcon } from "../icons/icons.mjs";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { setStringAsync } from "expo-clipboard";
|
|
6
|
+
|
|
7
|
+
//#region src/components/CopyButton.tsx
|
|
8
|
+
/** How long the control stays acknowledged before returning to its icon. */
|
|
9
|
+
const FEEDBACK_MS = 1500;
|
|
10
|
+
const LABELS = {
|
|
11
|
+
idle: "copy",
|
|
12
|
+
copied: "copied",
|
|
13
|
+
failed: "copying failed"
|
|
14
|
+
};
|
|
15
|
+
/** A quiet icon button that copies text and says, briefly, whether it worked. */
|
|
16
|
+
function CopyButton({ text, label, style }) {
|
|
17
|
+
const [state, setState] = useState("idle");
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (state === "idle") return void 0;
|
|
20
|
+
const timer = setTimeout(() => setState("idle"), FEEDBACK_MS);
|
|
21
|
+
return () => clearTimeout(timer);
|
|
22
|
+
}, [state]);
|
|
23
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
24
|
+
variant: "ghost",
|
|
25
|
+
size: "icon",
|
|
26
|
+
accessibilityLabel: label === void 0 ? LABELS[state] : `${LABELS[state]} ${label}`,
|
|
27
|
+
onPress: () => {
|
|
28
|
+
setStringAsync(text).then((saved) => setState(saved ? "copied" : "failed"), () => setState("failed"));
|
|
29
|
+
},
|
|
30
|
+
style,
|
|
31
|
+
children: state === "copied" ? /* @__PURE__ */ jsx(CheckIcon, {
|
|
32
|
+
size: 12,
|
|
33
|
+
color: "green"
|
|
34
|
+
}) : /* @__PURE__ */ jsx(CopyIcon, {
|
|
35
|
+
size: 12,
|
|
36
|
+
color: "faint"
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { CopyButton };
|
|
43
|
+
//# sourceMappingURL=CopyButton.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopyButton.mjs","names":["setStringAsync","useEffect","useState","StyleProp","ViewStyle","CheckIcon","CopyIcon","Button","FEEDBACK_MS","CopyState","LABELS","Readonly","Record","idle","copied","failed","CopyButtonProps","text","label","style","CopyButton","state","setState","undefined","timer","setTimeout","clearTimeout","then","saved"],"sources":["../../src/components/CopyButton.tsx"],"sourcesContent":["import { setStringAsync } from 'expo-clipboard';\nimport { useEffect, useState } from 'react';\nimport type { StyleProp, ViewStyle } from 'react-native';\n\nimport { CheckIcon, CopyIcon } from '../icons/icons';\nimport { Button } from './Button';\n\n/** How long the control stays acknowledged before returning to its icon. */\nconst FEEDBACK_MS = 1500;\n\ntype CopyState = 'idle' | 'copied' | 'failed';\n\nconst LABELS: Readonly<Record<CopyState, string>> = {\n idle: 'copy',\n copied: 'copied',\n failed: 'copying failed',\n};\n\nexport interface CopyButtonProps {\n /** The text the press puts on the clipboard. */\n text: string;\n /** What is copied, announced before the state, such as `path`. */\n label?: string;\n style?: StyleProp<ViewStyle>;\n}\n\n/** A quiet icon button that copies text and says, briefly, whether it worked. */\nexport function CopyButton({ text, label, style }: CopyButtonProps) {\n const [state, setState] = useState<CopyState>('idle');\n\n useEffect(() => {\n if (state === 'idle') return undefined;\n const timer = setTimeout(() => setState('idle'), FEEDBACK_MS);\n return () => clearTimeout(timer);\n }, [state]);\n\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n accessibilityLabel={label === undefined ? LABELS[state] : `${LABELS[state]} ${label}`}\n onPress={() => {\n setStringAsync(text).then(\n (saved) => setState(saved ? 'copied' : 'failed'),\n () => setState('failed'),\n );\n }}\n style={style}\n >\n {state === 'copied' ? <CheckIcon size={12} color=\"green\" /> : <CopyIcon size={12} color=\"faint\" />}\n </Button>\n );\n}\n"],"mappings":";;;;;;;;AAQA,MAAMQ,cAAc;AAIpB,MAAME,SAA8C;CAClDG,MAAM;CACNC,QAAQ;CACRC,QAAQ;AACV;;AAWA,SAAgBK,WAAW,EAAEH,MAAMC,OAAOC,SAA0B;CAClE,MAAM,CAACE,OAAOC,YAAYpB,SAAoB,MAAM;CAEpDD,gBAAgB;EACd,IAAIoB,UAAU,QAAQ,OAAOE;EAC7B,MAAMC,QAAQC,iBAAiBH,SAAS,MAAM,GAAGd,WAAW;EAC5D,aAAakB,aAAaF,KAAK;CACjC,GAAG,CAACH,KAAK,CAAC;CAEV,OACE,oBAAC,QAAD;EACE,SAAQ;EACR,MAAK;EACL,oBAAoBH,UAAUK,SAAYb,OAAOW,SAAS,GAAGX,OAAOW,OAAM,GAAIH;EAC9E,eAAe;GACblB,eAAeiB,IAAI,CAAC,CAACU,MAClBC,UAAUN,SAASM,QAAQ,WAAW,QAAQ,SACzCN,SAAS,QAAQ,CACzB;EACF;EACOH;YAENE,UAAU,WAAW,oBAAC,WAAD;GAAW,MAAM;GAAI,OAAM;EAAO,KAAM,oBAAC,UAAD;GAAU,MAAM;GAAI,OAAM;EAAO;CACzF;AAEZ"}
|
|
@@ -4,14 +4,14 @@ import { Button } from "./Button.mjs";
|
|
|
4
4
|
import { CloseIcon } from "../icons/icons.mjs";
|
|
5
5
|
import { useControllable } from "../lib/useControllable.mjs";
|
|
6
6
|
import { View } from "react-native-unistyles/components/native/View";
|
|
7
|
-
import {
|
|
7
|
+
import { Text } from "react-native-unistyles/components/native/Text";
|
|
8
8
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
9
9
|
import { Easing, Modal, Platform } from "react-native";
|
|
10
|
-
import {
|
|
10
|
+
import { Animated } from "react-native-unistyles/components/native/Animated";
|
|
11
|
+
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
11
12
|
import { createContext, useContext, useEffect, useRef } from "react";
|
|
12
13
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
14
|
import { Pressable } from "react-native-unistyles/components/native/Pressable";
|
|
14
|
-
import { Animated } from "react-native-unistyles/components/native/Animated";
|
|
15
15
|
|
|
16
16
|
//#region src/components/Dialog.tsx
|
|
17
17
|
/** `bg-po-deep/70`. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DotTone } from "@agimon-ai/po-web-components/nativeTheme";
|
|
2
1
|
import { StyleProp, ViewStyle } from "react-native";
|
|
2
|
+
import { DotTone } from "@agimon-ai/po-web-components/nativeTheme";
|
|
3
3
|
//#region src/components/Dot.d.ts
|
|
4
4
|
type DotTone$1 = DotTone;
|
|
5
5
|
export type DotSize = 'xs' | 'sm' | 'md' | 'lg';
|
package/dist/components/Dot.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
2
1
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
2
|
+
import { Animated } from "react-native-unistyles/components/native/Animated";
|
|
3
|
+
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
3
4
|
import { useEffect, useRef } from "react";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
-
import { Animated } from "react-native-unistyles/components/native/Animated";
|
|
6
6
|
|
|
7
7
|
//#region src/components/Dot.tsx
|
|
8
8
|
/** `bg-po-faint/40`: a thing that exists but is not live. */
|
|
@@ -6,8 +6,8 @@ import { CheckIcon } from "../icons/icons.mjs";
|
|
|
6
6
|
import { useControllable } from "../lib/useControllable.mjs";
|
|
7
7
|
import { SheetFrame } from "./SheetFrame.mjs";
|
|
8
8
|
import { View } from "react-native-unistyles/components/native/View";
|
|
9
|
-
import { StyleSheet } from "react-native-unistyles";
|
|
10
9
|
import { Text } from "react-native-unistyles/components/native/Text";
|
|
10
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
11
11
|
import { createContext, useContext } from "react";
|
|
12
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { Pressable } from "react-native-unistyles/components/native/Pressable";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PresentedLine } from "@agimon-ai/po-web-components/text";
|
|
2
|
+
import { ViewProps } from "react-native";
|
|
3
|
+
//#region src/components/HashlineLines.d.ts
|
|
4
|
+
export interface HashlineLinesProps extends Omit<ViewProps, 'children'> {
|
|
5
|
+
lines: readonly PresentedLine[];
|
|
6
|
+
/** Width of the line-number column, in characters, from `hashlineBody`. */
|
|
7
|
+
gutter: number;
|
|
8
|
+
/** The file a body of bare anchored lines came from, for highlighting. */
|
|
9
|
+
path?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
export declare function HashlineLines({ lines, gutter, path, style, ...props }: HashlineLinesProps): import("react").JSX.Element;
|
|
12
|
+
//#endregion
|
|
13
|
+
//# sourceMappingURL=HashlineLines.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HashlineLines.d.mts","names":[],"sources":["../../src/components/HashlineLines.tsx"],"mappings":";;;iBA0BiB,2BAA2B,KAAK;EAC/C,gBAAgB;;EAEhB;;EAEA;;wBAsCc,gBAAgB,OAAO,QAAQ,MAAM,UAAU,SAAS,qCAAkB,IAAA"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { fontOf } from "../lib/fonts.mjs";
|
|
2
|
+
import { SyntaxLine } from "./SyntaxLine.mjs";
|
|
3
|
+
import { detectGrammar, hashlineGroups, hashlineGroupsKey, highlightToLines } from "@agimon-ai/po-web-components/text";
|
|
4
|
+
import { View } from "react-native-unistyles/components/native/View";
|
|
5
|
+
import { Text } from "react-native-unistyles/components/native/Text";
|
|
6
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
7
|
+
import { useEffect, useMemo, useState } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
|
|
10
|
+
//#region src/components/HashlineLines.tsx
|
|
11
|
+
const NO_SPANS = /* @__PURE__ */ new Map();
|
|
12
|
+
/** Spans per presented-line index, kept with the body they belong to, as the web's hook. */
|
|
13
|
+
function useHashlineSpans(lines, path) {
|
|
14
|
+
const groups = useMemo(() => hashlineGroups(lines, path), [lines, path]);
|
|
15
|
+
const key = hashlineGroupsKey(groups);
|
|
16
|
+
const [done, setDone] = useState();
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
let live = true;
|
|
19
|
+
const next = /* @__PURE__ */ new Map();
|
|
20
|
+
const work = groups.map(async (group) => {
|
|
21
|
+
const grammar = detectGrammar({
|
|
22
|
+
path: group.path,
|
|
23
|
+
text: group.text
|
|
24
|
+
});
|
|
25
|
+
if (grammar === void 0) return;
|
|
26
|
+
const highlighted = await highlightToLines(group.text, grammar);
|
|
27
|
+
if (highlighted === void 0) return;
|
|
28
|
+
for (const [offset, index] of group.indices.entries()) {
|
|
29
|
+
const line = highlighted[offset];
|
|
30
|
+
if (line !== void 0) next.set(index, line);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
Promise.allSettled(work).then(() => {
|
|
34
|
+
if (live && next.size > 0) setDone({
|
|
35
|
+
key,
|
|
36
|
+
spans: next
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
return () => {
|
|
40
|
+
live = false;
|
|
41
|
+
};
|
|
42
|
+
}, [key]);
|
|
43
|
+
return done?.key === key ? done.spans : NO_SPANS;
|
|
44
|
+
}
|
|
45
|
+
function HashlineLines({ lines, gutter, path, style, ...props }) {
|
|
46
|
+
const spans = useHashlineSpans(lines, path);
|
|
47
|
+
return /* @__PURE__ */ jsx(View, {
|
|
48
|
+
style,
|
|
49
|
+
...props,
|
|
50
|
+
children: lines.map((line, index) => {
|
|
51
|
+
if (line.type === "file") return /* @__PURE__ */ jsx(Text, {
|
|
52
|
+
numberOfLines: 1,
|
|
53
|
+
style: [
|
|
54
|
+
styles.mono,
|
|
55
|
+
styles.faint,
|
|
56
|
+
index > 0 && styles.fileGap
|
|
57
|
+
],
|
|
58
|
+
children: line.path
|
|
59
|
+
}, index);
|
|
60
|
+
if (line.type === "plain") return /* @__PURE__ */ jsx(Text, {
|
|
61
|
+
selectable: true,
|
|
62
|
+
style: [styles.mono, styles.dim],
|
|
63
|
+
children: line.text
|
|
64
|
+
}, index);
|
|
65
|
+
const { value } = line;
|
|
66
|
+
const match = value.marker === "match";
|
|
67
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
68
|
+
style: styles.row,
|
|
69
|
+
children: [
|
|
70
|
+
value.marker !== void 0 ? /* @__PURE__ */ jsx(Text, {
|
|
71
|
+
style: [styles.mono, match ? styles.marker : styles.faint],
|
|
72
|
+
children: match ? ">>" : " "
|
|
73
|
+
}) : null,
|
|
74
|
+
/* @__PURE__ */ jsx(Text, {
|
|
75
|
+
style: [styles.mono, styles.faint],
|
|
76
|
+
children: String(value.line).padStart(gutter)
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ jsx(SyntaxLine, {
|
|
79
|
+
selectable: true,
|
|
80
|
+
spans: spans.get(index),
|
|
81
|
+
text: value.content,
|
|
82
|
+
style: [
|
|
83
|
+
styles.mono,
|
|
84
|
+
styles.content,
|
|
85
|
+
match ? styles.hi : styles.text
|
|
86
|
+
]
|
|
87
|
+
})
|
|
88
|
+
]
|
|
89
|
+
}, index);
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const styles = StyleSheet.create((theme) => ({
|
|
94
|
+
row: {
|
|
95
|
+
flexDirection: "row",
|
|
96
|
+
gap: theme.spacing(2),
|
|
97
|
+
uni__dependencies: [0]
|
|
98
|
+
},
|
|
99
|
+
fileGap: {
|
|
100
|
+
marginTop: theme.spacing(1),
|
|
101
|
+
uni__dependencies: [0]
|
|
102
|
+
},
|
|
103
|
+
mono: {
|
|
104
|
+
fontFamily: fontOf(theme.fontFamily.mono),
|
|
105
|
+
fontSize: theme.fontSize.sm,
|
|
106
|
+
lineHeight: theme.lineHeightRelaxed.sm,
|
|
107
|
+
uni__dependencies: [0]
|
|
108
|
+
},
|
|
109
|
+
content: {
|
|
110
|
+
flex: 1,
|
|
111
|
+
minWidth: 0
|
|
112
|
+
},
|
|
113
|
+
marker: {
|
|
114
|
+
color: theme.colors.blue,
|
|
115
|
+
uni__dependencies: [0]
|
|
116
|
+
},
|
|
117
|
+
faint: {
|
|
118
|
+
color: theme.colors.faint,
|
|
119
|
+
uni__dependencies: [0]
|
|
120
|
+
},
|
|
121
|
+
dim: {
|
|
122
|
+
color: theme.colors.dim,
|
|
123
|
+
uni__dependencies: [0]
|
|
124
|
+
},
|
|
125
|
+
text: {
|
|
126
|
+
color: theme.colors.text,
|
|
127
|
+
uni__dependencies: [0]
|
|
128
|
+
},
|
|
129
|
+
hi: {
|
|
130
|
+
color: theme.colors.hi,
|
|
131
|
+
uni__dependencies: [0]
|
|
132
|
+
}
|
|
133
|
+
}));
|
|
134
|
+
|
|
135
|
+
//#endregion
|
|
136
|
+
export { HashlineLines };
|
|
137
|
+
//# sourceMappingURL=HashlineLines.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HashlineLines.mjs","names":["detectGrammar","hashlineGroups","hashlineGroupsKey","highlightToLines","PresentedLine","SyntaxSpan","useEffect","useMemo","useState","ViewProps","StyleSheet","fontOf","SyntaxLine","HashlineLinesProps","Omit","lines","gutter","path","NO_SPANS","ReadonlyMap","Map","useHashlineSpans","groups","key","done","setDone","spans","live","next","work","map","group","grammar","text","undefined","highlighted","offset","index","indices","entries","line","set","Promise","allSettled","then","size","HashlineLines","style","props","type","styles","mono","faint","fileGap","dim","value","match","marker","row","String","padStart","get","content","hi","create","theme","flexDirection","gap","spacing","uni__dependencies","marginTop","fontFamily","fontSize","sm","lineHeight","lineHeightRelaxed","flex","minWidth","color","colors","blue"],"sources":["../../src/components/HashlineLines.tsx"],"sourcesContent":["import {\n detectGrammar,\n hashlineGroups,\n hashlineGroupsKey,\n highlightToLines,\n type PresentedLine,\n type SyntaxSpan,\n} from '@agimon-ai/po-web-components/text';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Text, View, type ViewProps } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport { fontOf } from '../lib/fonts';\nimport { SyntaxLine } from './SyntaxLine';\n\n/*\n * The anchored body shared by hashline results, as the web's HashlineLines: a\n * file heading per group, a right-aligned line-number gutter, and a `>>`\n * marker on grep matches. Mono type makes a padded number the gutter, so the\n * column needs no measuring.\n *\n * The anchored lines are coloured with the web's grammars and palette when the\n * body names a file, or when `path` names one. Colour arrives late and never\n * blocks the text: an unhighlighted body is the same body without the colours.\n */\n\nexport interface HashlineLinesProps extends Omit<ViewProps, 'children'> {\n lines: readonly PresentedLine[];\n /** Width of the line-number column, in characters, from `hashlineBody`. */\n gutter: number;\n /** The file a body of bare anchored lines came from, for highlighting. */\n path?: string | undefined;\n}\n\nconst NO_SPANS: ReadonlyMap<number, readonly SyntaxSpan[]> = new Map();\n\n/** Spans per presented-line index, kept with the body they belong to, as the web's hook. */\nfunction useHashlineSpans(lines: readonly PresentedLine[], path: string | undefined) {\n const groups = useMemo(() => hashlineGroups(lines, path), [lines, path]);\n const key = hashlineGroupsKey(groups);\n const [done, setDone] = useState<{ key: string; spans: ReadonlyMap<number, readonly SyntaxSpan[]> }>();\n\n useEffect(() => {\n let live = true;\n const next = new Map<number, readonly SyntaxSpan[]>();\n const work = groups.map(async (group) => {\n const grammar = detectGrammar({ path: group.path, text: group.text });\n if (grammar === undefined) return;\n const highlighted = await highlightToLines(group.text, grammar);\n if (highlighted === undefined) return;\n for (const [offset, index] of group.indices.entries()) {\n const line = highlighted[offset];\n if (line !== undefined) next.set(index, line);\n }\n });\n // A grammar that fails to load leaves its run plain: colour is decoration.\n void Promise.allSettled(work).then(() => {\n if (live && next.size > 0) setDone({ key, spans: next });\n });\n return () => {\n live = false;\n };\n // The groups are rebuilt with the lines; their key is what actually changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key]);\n\n return done?.key === key ? done.spans : NO_SPANS;\n}\n\nexport function HashlineLines({ lines, gutter, path, style, ...props }: HashlineLinesProps) {\n const spans = useHashlineSpans(lines, path);\n return (\n <View style={style} {...props}>\n {lines.map((line, index) => {\n if (line.type === 'file') {\n return (\n <Text key={index} numberOfLines={1} style={[styles.mono, styles.faint, index > 0 && styles.fileGap]}>\n {line.path}\n </Text>\n );\n }\n if (line.type === 'plain') {\n return (\n <Text key={index} selectable style={[styles.mono, styles.dim]}>\n {line.text}\n </Text>\n );\n }\n const { value } = line;\n const match = value.marker === 'match';\n return (\n <View key={index} style={styles.row}>\n {value.marker !== undefined ? (\n <Text style={[styles.mono, match ? styles.marker : styles.faint]}>{match ? '>>' : ' '}</Text>\n ) : null}\n <Text style={[styles.mono, styles.faint]}>{String(value.line).padStart(gutter)}</Text>\n <SyntaxLine\n selectable\n spans={spans.get(index)}\n text={value.content}\n style={[styles.mono, styles.content, match ? styles.hi : styles.text]}\n />\n </View>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create((theme) => ({\n row: { flexDirection: 'row', gap: theme.spacing(2) },\n fileGap: { marginTop: theme.spacing(1) },\n mono: {\n fontFamily: fontOf(theme.fontFamily.mono),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeightRelaxed.sm,\n },\n content: { flex: 1, minWidth: 0 },\n marker: { color: theme.colors.blue },\n faint: { color: theme.colors.faint },\n dim: { color: theme.colors.dim },\n text: { color: theme.colors.text },\n hi: { color: theme.colors.hi },\n}));\n"],"mappings":";;;;;;;;;;AAkCA,MAAMkB,2BAAuD,IAAIE,IAAI;;AAGrE,SAASC,iBAAiBN,OAAiCE,MAA0B;CACnF,MAAMK,SAASf,cAAcN,eAAec,OAAOE,IAAI,GAAG,CAACF,OAAOE,IAAI,CAAC;CACvE,MAAMM,MAAMrB,kBAAkBoB,MAAM;CACpC,MAAM,CAACE,MAAMC,WAAWjB,SAA6E;CAErGF,gBAAgB;EACd,IAAIqB,OAAO;EACX,MAAMC,uBAAO,IAAIR,IAAmC;EACpD,MAAMS,OAAOP,OAAOQ,IAAI,OAAOC,UAAU;GACvC,MAAMC,UAAUhC,cAAc;IAAEiB,MAAMc,MAAMd;IAAMgB,MAAMF,MAAME;GAAK,CAAC;GACpE,IAAID,YAAYE,QAAW;GAC3B,MAAMC,cAAc,MAAMhC,iBAAiB4B,MAAME,MAAMD,OAAO;GAC9D,IAAIG,gBAAgBD,QAAW;GAC/B,KAAK,MAAM,CAACE,QAAQC,UAAUN,MAAMO,QAAQC,QAAQ,GAAG;IACrD,MAAMC,OAAOL,YAAYC;IACzB,IAAII,SAASN,QAAWN,KAAKa,IAAIJ,OAAOG,IAAI;GAC9C;EACF,CAAC;EAED,AAAKE,QAAQC,WAAWd,IAAI,CAAC,CAACe,WAAW;GACvC,IAAIjB,QAAQC,KAAKiB,OAAO,GAAGpB,QAAQ;IAAEF;IAAKG,OAAOE;GAAK,CAAC;EACzD,CAAC;EACD,aAAa;GACXD,OAAO;EACT;CAGF,GAAG,CAACJ,GAAG,CAAC;CAER,OAAOC,MAAMD,QAAQA,MAAMC,KAAKE,QAAQR;AAC1C;AAEA,SAAgB4B,cAAc,EAAE/B,OAAOC,QAAQC,MAAM8B,OAAO,GAAGC,SAA6B;CAC1F,MAAMtB,QAAQL,iBAAiBN,OAAOE,IAAI;CAC1C,OACE,oBAAC,MAAD;EAAa8B;EAAO,GAAIC;YACrBjC,MAAMe,KAAKU,MAAMH,UAAU;GAC1B,IAAIG,KAAKS,SAAS,QAChB,OACE,oBAAC,MAAD;IAAkB,eAAe;IAAG,OAAO;KAACC,OAAOC;KAAMD,OAAOE;KAAOf,QAAQ,KAAKa,OAAOG;IAAO;cAC/Fb,KAAKvB;GACF,GAFKoB,KAEL;GAGV,IAAIG,KAAKS,SAAS,SAChB,OACE,oBAAC,MAAD;IAAkB;IAAW,OAAO,CAACC,OAAOC,MAAMD,OAAOI,GAAG;cACzDd,KAAKP;GACF,GAFKI,KAEL;GAGV,MAAM,EAAEkB,UAAUf;GAClB,MAAMgB,QAAQD,MAAME,WAAW;GAC/B,OACE,qBAAC,MAAD;IAAkB,OAAOP,OAAOQ;cAAhC;KACGH,MAAME,WAAWvB,SAChB,oBAAC,MAAD;MAAM,OAAO,CAACgB,OAAOC,MAAMK,QAAQN,OAAOO,SAASP,OAAOE,KAAK;gBAAII,QAAQ,OAAO;KAAW,KAC3F;KACJ,oBAAC,MAAD;MAAM,OAAO,CAACN,OAAOC,MAAMD,OAAOE,KAAK;gBAAIO,OAAOJ,MAAMf,IAAI,CAAC,CAACoB,SAAS5C,MAAM;KAAQ;KACrF,oBAAC,YAAD;MACE;MACA,OAAOU,MAAMmC,IAAIxB,KAAK;MACtB,MAAMkB,MAAMO;MACZ,OAAO;OAACZ,OAAOC;OAAMD,OAAOY;OAASN,QAAQN,OAAOa,KAAKb,OAAOjB;MAAI;KAAE;IAEpE;MAXKI,KAWL;EAEV,CAAC;CACG;AAEV;AAEA,MAAMa,SAASxC,WAAWsD,QAAQC,WAAW;CAC3CP,KAAK;EAAEQ,eAAe;EAAOC,KAAKF,MAAMG,QAAQ,CAAC;EAACC,mBAAA,CAAA,CAAA;CAAC;CACnDhB,SAAS;EAAEiB,WAAWL,MAAMG,QAAQ,CAAC;EAACC,mBAAA,CAAA,CAAA;CAAC;CACvClB,MAAM;EACJoB,YAAY5D,OAAOsD,MAAMM,WAAWpB,IAAI;EACxCqB,UAAUP,MAAMO,SAASC;EACzBC,YAAYT,MAAMU,kBAAkBF;EAAEJ,mBAAA,CAAA,CAAA;CACxC;CACAP,SAAS;EAAEc,MAAM;EAAGC,UAAU;CAAE;CAChCpB,QAAQ;EAAEqB,OAAOb,MAAMc,OAAOC;EAAIX,mBAAA,CAAA,CAAA;CAAC;CACnCjB,OAAO;EAAE0B,OAAOb,MAAMc,OAAO3B;EAAKiB,mBAAA,CAAA,CAAA;CAAC;CACnCf,KAAK;EAAEwB,OAAOb,MAAMc,OAAOzB;EAAGe,mBAAA,CAAA,CAAA;CAAC;CAC/BpC,MAAM;EAAE6C,OAAOb,MAAMc,OAAO9C;EAAIoC,mBAAA,CAAA,CAAA;CAAC;CACjCN,IAAI;EAAEe,OAAOb,MAAMc,OAAOhB;EAAEM,mBAAA,CAAA,CAAA;CAAC;AAC/B,EAAE"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fontOf } from "../lib/fonts.mjs";
|
|
2
2
|
import { useInsideSheet } from "../lib/insideSheet.mjs";
|
|
3
|
-
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
4
3
|
import { StyleSheet, useUnistyles, withUnistyles } from "react-native-unistyles";
|
|
4
|
+
import { withAlpha } from "@agimon-ai/po-web-components/nativeTheme";
|
|
5
5
|
import { useState } from "react";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
import { BottomSheetTextInput } from "@gorhom/bottom-sheet";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fontOf } from "../lib/fonts.mjs";
|
|
2
|
-
import { StyleSheet } from "react-native-unistyles";
|
|
3
2
|
import { Text } from "react-native-unistyles/components/native/Text";
|
|
3
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
|
|
6
6
|
//#region src/components/Label.tsx
|
package/dist/components/List.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { fontOf } from "../lib/fonts.mjs";
|
|
2
2
|
import { ChevronRightIcon } from "../icons/icons.mjs";
|
|
3
3
|
import { View } from "react-native-unistyles/components/native/View";
|
|
4
|
+
import { Text } from "react-native-unistyles/components/native/Text";
|
|
4
5
|
import { StyleSheet } from "react-native-unistyles";
|
|
5
6
|
import { Platform } from "react-native";
|
|
6
|
-
import { Text } from "react-native-unistyles/components/native/Text";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { Pressable } from "react-native-unistyles/components/native/Pressable";
|
|
9
9
|
import { FlashList } from "@shopify/flash-list";
|
|
@@ -5,11 +5,18 @@
|
|
|
5
5
|
* contract as the web Markdown's handler.
|
|
6
6
|
*/
|
|
7
7
|
export type FileLinkHandler = (text: string, explicit?: boolean) => (() => void) | undefined;
|
|
8
|
+
/** Loads a relative image path from the host; the same contract as the web Markdown's `loadImage`. */
|
|
9
|
+
export type MarkdownImageLoader = (path: string) => Promise<{
|
|
10
|
+
url: string;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
}>;
|
|
8
13
|
export interface MarkdownProps {
|
|
9
14
|
text: string;
|
|
10
15
|
onFileLink?: FileLinkHandler;
|
|
16
|
+
/** Loads relative image paths; without it they show as unavailable. */
|
|
17
|
+
loadImage?: MarkdownImageLoader;
|
|
11
18
|
}
|
|
12
19
|
/** Markdown in Po's shared presentation, parsed by the package's own small parser. */
|
|
13
|
-
export declare function Markdown({ text, onFileLink }: MarkdownProps): import("react").JSX.Element;
|
|
20
|
+
export declare function Markdown({ text, onFileLink, loadImage }: MarkdownProps): import("react").JSX.Element;
|
|
14
21
|
//#endregion
|
|
15
22
|
//# sourceMappingURL=Markdown.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Markdown.d.mts","names":[],"sources":["../../src/components/Markdown.tsx"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"Markdown.d.mts","names":[],"sources":["../../src/components/Markdown.tsx"],"mappings":";;;;;;YAoBY,mBAAmB,cAAc;;YAMjC,uBAAuB,iBAAiB;EAAU;EAAa;;iBA0O1D;EACf;EACA,aAAa;;EAEb,YAAY;;;wBAIE,WAAW,MAAM,YAAY,aAAa,gCAAa,IAAA"}
|