@heyramzi/ui 2.17.0 → 2.18.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/dist/thread/logic.js +11 -30
- package/package.json +1 -1
- package/src/thread/README.md +2 -2
- package/src/thread/index.ts +0 -1
- package/src/thread/logic.ts +2 -19
- package/src/thread/thread.svelte +2 -15
- package/src/thread/types.ts +2 -10
package/dist/thread/logic.js
CHANGED
|
@@ -57,28 +57,17 @@ export function resolveThreadLabels(overrides) {
|
|
|
57
57
|
export function fillCount(label, count) {
|
|
58
58
|
return label.replaceAll("{count}", String(count));
|
|
59
59
|
}
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
...events.map((event, index) => ({
|
|
72
|
-
at: at(event.at),
|
|
73
|
-
index: nodes.length + index,
|
|
74
|
-
event
|
|
75
|
-
})),
|
|
76
|
-
...entries.map((entry, index) => ({
|
|
77
|
-
at: at(entry.at),
|
|
78
|
-
index: nodes.length + events.length + index,
|
|
79
|
-
entry
|
|
80
|
-
}))
|
|
81
|
-
].toSorted((a, b) => a.at - b.at || a.index - b.index);
|
|
60
|
+
/** Conversations and events in time order, each run of events between two conversations as one item. */
|
|
61
|
+
export function interleave(nodes, events) {
|
|
62
|
+
const timed = [...nodes.map((node, index) => ({
|
|
63
|
+
at: at(node.comment.createdAt),
|
|
64
|
+
index,
|
|
65
|
+
node
|
|
66
|
+
})), ...events.map((event, index) => ({
|
|
67
|
+
at: at(event.at),
|
|
68
|
+
index: nodes.length + index,
|
|
69
|
+
event
|
|
70
|
+
}))].toSorted((a, b) => a.at - b.at || a.index - b.index);
|
|
82
71
|
const items = [];
|
|
83
72
|
for (const row of timed) {
|
|
84
73
|
if ("node" in row) {
|
|
@@ -89,14 +78,6 @@ export function interleave(nodes, events, entries = []) {
|
|
|
89
78
|
});
|
|
90
79
|
continue;
|
|
91
80
|
}
|
|
92
|
-
if ("entry" in row) {
|
|
93
|
-
items.push({
|
|
94
|
-
type: "entry",
|
|
95
|
-
key: `entry-${row.entry.id}`,
|
|
96
|
-
entry: row.entry
|
|
97
|
-
});
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
81
|
const last = items.at(-1);
|
|
101
82
|
if (last?.type === "events") last.events.push(row.event);
|
|
102
83
|
else items.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heyramzi/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "Svelte 5 UI for apps: primitives, effects and animations, plus work (tasks and docs), charts, slides, an editor, onboarding and a canvas as subpaths.",
|
|
5
5
|
"homepage": "https://ui.heyramzi.com",
|
|
6
6
|
"license": "MIT",
|
package/src/thread/README.md
CHANGED
|
@@ -24,8 +24,8 @@ One comment thread for any subject: a task, a project, a doc or a diagram. The t
|
|
|
24
24
|
- **Resolve.** Pass `onResolve` and each root gets a check. Resolved roots fold away behind a "Show N resolved" button.
|
|
25
25
|
- **Anchor.** `anchor` carries `{ nodeId, dx, dy, x, y }` for a canvas pin. A pinned comment shows a chip, and `onAnchor` fires on a click so the canvas can move to the node. `anchorChip` replaces the chip.
|
|
26
26
|
- **Attachments.** The `attachments` snippet draws under a comment's body.
|
|
27
|
-
- **Events.** `events` takes `ThreadEvent`s (a whole sentence, a time, an optional Phosphor icon) and draws each as one `Trace` line between the conversations, in time order. `whenEvent(event)` formats its time. `interleave(nodes, events
|
|
28
|
-
- **
|
|
27
|
+
- **Events.** `events` takes `ThreadEvent`s (a whole sentence, a time, an optional Phosphor icon) and draws each as one `Trace` line between the conversations, in time order. `whenEvent(event)` formats its time. `interleave(nodes, events)` gives the same order without the component.
|
|
28
|
+
- **Footer.** `footer` draws above the composer, such as an agent's question waiting on an answer. `onPost` decides where a root post goes.
|
|
29
29
|
- **Heading.** `heading={false}` keeps the title for screen readers only, for a thread its tab already names.
|
|
30
30
|
- **Long bodies.** A body over 6 lines folds behind `showMore` and `showLess`.
|
|
31
31
|
- **Labels.** Every string comes from `labels`, a partial of `ThreadLabels`. `showResolved` holds a `{count}` slot. `when(comment)` formats the time.
|
package/src/thread/index.ts
CHANGED
package/src/thread/logic.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ThreadComment,
|
|
3
|
-
ThreadEntry,
|
|
4
3
|
ThreadEvent,
|
|
5
4
|
ThreadItem,
|
|
6
5
|
ThreadLabels,
|
|
@@ -72,23 +71,11 @@ export function fillCount(label: string, count: number): string {
|
|
|
72
71
|
return label.replaceAll("{count}", String(count));
|
|
73
72
|
}
|
|
74
73
|
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
* other items as one item.
|
|
78
|
-
*/
|
|
79
|
-
export function interleave(
|
|
80
|
-
nodes: ThreadNode[],
|
|
81
|
-
events: ThreadEvent[],
|
|
82
|
-
entries: ThreadEntry[] = [],
|
|
83
|
-
): ThreadItem[] {
|
|
74
|
+
/** Conversations and events in time order, each run of events between two conversations as one item. */
|
|
75
|
+
export function interleave(nodes: ThreadNode[], events: ThreadEvent[]): ThreadItem[] {
|
|
84
76
|
const timed = [
|
|
85
77
|
...nodes.map((node, index) => ({ at: at(node.comment.createdAt), index, node })),
|
|
86
78
|
...events.map((event, index) => ({ at: at(event.at), index: nodes.length + index, event })),
|
|
87
|
-
...entries.map((entry, index) => ({
|
|
88
|
-
at: at(entry.at),
|
|
89
|
-
index: nodes.length + events.length + index,
|
|
90
|
-
entry,
|
|
91
|
-
})),
|
|
92
79
|
].toSorted((a, b) => a.at - b.at || a.index - b.index);
|
|
93
80
|
const items: ThreadItem[] = [];
|
|
94
81
|
for (const row of timed) {
|
|
@@ -96,10 +83,6 @@ export function interleave(
|
|
|
96
83
|
items.push({ type: "node", key: row.node.comment.id, node: row.node });
|
|
97
84
|
continue;
|
|
98
85
|
}
|
|
99
|
-
if ("entry" in row) {
|
|
100
|
-
items.push({ type: "entry", key: `entry-${row.entry.id}`, entry: row.entry });
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
86
|
const last = items.at(-1);
|
|
104
87
|
if (last?.type === "events") last.events.push(row.event);
|
|
105
88
|
else items.push({ type: "events", key: row.event.id, events: [row.event] });
|
package/src/thread/thread.svelte
CHANGED
|
@@ -15,13 +15,7 @@
|
|
|
15
15
|
resolveThreadLabels,
|
|
16
16
|
resolvedCount,
|
|
17
17
|
} from "./logic.js";
|
|
18
|
-
import type {
|
|
19
|
-
ThreadComment,
|
|
20
|
-
ThreadEntry,
|
|
21
|
-
ThreadEvent,
|
|
22
|
-
ThreadLabels,
|
|
23
|
-
ThreadPost,
|
|
24
|
-
} from "./types.js";
|
|
18
|
+
import type { ThreadComment, ThreadEvent, ThreadLabels, ThreadPost } from "./types.js";
|
|
25
19
|
|
|
26
20
|
interface Props {
|
|
27
21
|
comments: ThreadComment[];
|
|
@@ -54,9 +48,6 @@
|
|
|
54
48
|
canEdit?: (comment: ThreadComment) => boolean;
|
|
55
49
|
/** False hides the visible title, for a thread already named by its tab. Screen readers still get it. */
|
|
56
50
|
heading?: boolean;
|
|
57
|
-
/** Rows the host draws through `entry`, placed in time among the comments. */
|
|
58
|
-
entries?: ThreadEntry[];
|
|
59
|
-
entry?: Snippet<[ThreadEntry]>;
|
|
60
51
|
/** Drawn above the composer, such as a question waiting on an answer. */
|
|
61
52
|
footer?: Snippet;
|
|
62
53
|
class?: string;
|
|
@@ -80,8 +71,6 @@
|
|
|
80
71
|
onAnchor,
|
|
81
72
|
canEdit = () => false,
|
|
82
73
|
heading = true,
|
|
83
|
-
entries = [],
|
|
84
|
-
entry,
|
|
85
74
|
footer,
|
|
86
75
|
class: className,
|
|
87
76
|
}: Props = $props();
|
|
@@ -91,7 +80,7 @@
|
|
|
91
80
|
let resolved = $derived(resolvedCount(nodes));
|
|
92
81
|
let showResolved = $state(false);
|
|
93
82
|
let shown = $derived(showResolved ? nodes : nodes.filter((node) => !node.comment.resolved));
|
|
94
|
-
let items = $derived(interleave(shown, events
|
|
83
|
+
let items = $derived(interleave(shown, events));
|
|
95
84
|
|
|
96
85
|
function shortDate(at: string): string {
|
|
97
86
|
return new Intl.DateTimeFormat(locale, { month: "short", day: "numeric" }).format(new Date(at));
|
|
@@ -321,8 +310,6 @@
|
|
|
321
310
|
{#each items as item (item.key)}
|
|
322
311
|
{#if item.type === "events"}
|
|
323
312
|
<li><ThreadEvents events={item.events} when={whenEvent} /></li>
|
|
324
|
-
{:else if item.type === "entry"}
|
|
325
|
-
<li class="min-w-0">{@render entry?.(item.entry)}</li>
|
|
326
313
|
{:else}
|
|
327
314
|
{@const node = item.node}
|
|
328
315
|
<li
|
package/src/thread/types.ts
CHANGED
|
@@ -59,18 +59,10 @@ export type ThreadEvent = {
|
|
|
59
59
|
icon?: PhosphorIcon;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
/**
|
|
63
|
-
export type ThreadEntry = {
|
|
64
|
-
id: string;
|
|
65
|
-
/** ISO timestamp. */
|
|
66
|
-
at: string;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/** The thread in time order: a conversation, a run of events between two of them, or a host's entry. */
|
|
62
|
+
/** The thread in time order: a conversation, or a run of events between two of them. */
|
|
70
63
|
export type ThreadItem =
|
|
71
64
|
| { type: "node"; key: string; node: ThreadNode }
|
|
72
|
-
| { type: "events"; key: string; events: ThreadEvent[] }
|
|
73
|
-
| { type: "entry"; key: string; entry: ThreadEntry };
|
|
65
|
+
| { type: "events"; key: string; events: ThreadEvent[] };
|
|
74
66
|
|
|
75
67
|
export type ThreadLabels = {
|
|
76
68
|
title: string;
|