@crewlethq/ui 0.19.0 → 0.20.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.
Files changed (42) hide show
  1. package/README.md +22 -3
  2. package/dist/CommentThread/CommentThread.d.ts +85 -0
  3. package/dist/CommentThread/index.d.ts +3 -0
  4. package/dist/CommentThread/index.js +16 -0
  5. package/dist/CommentThread-7VXOFTZO.css +90 -0
  6. package/dist/ConflictNote/ConflictNote.d.ts +42 -0
  7. package/dist/ConflictNote/index.d.ts +3 -0
  8. package/dist/ConflictNote/index.js +4 -0
  9. package/dist/ConflictNote-DH77PYF7.css +27 -0
  10. package/dist/DiffView/DiffView.d.ts +59 -0
  11. package/dist/DiffView/diff.d.ts +97 -0
  12. package/dist/DiffView/index.d.ts +5 -0
  13. package/dist/DiffView/index.js +3 -0
  14. package/dist/DiffView-RVLIHTKG.css +91 -0
  15. package/dist/LinkInterstitial/index.js +2 -2
  16. package/dist/PeopleRail/PeopleRail.d.ts +52 -0
  17. package/dist/PeopleRail/index.d.ts +3 -0
  18. package/dist/PeopleRail/index.js +11 -0
  19. package/dist/PeopleRail-R64WVOSH.css +75 -0
  20. package/dist/SheetGrid/index.js +3 -3
  21. package/dist/TableCells/TableCells.d.ts +153 -0
  22. package/dist/TableCells/index.d.ts +3 -0
  23. package/dist/TableCells/index.js +10 -0
  24. package/dist/TableCells-3VN5N2M3.css +104 -0
  25. package/dist/VersionCompare/VersionCompare.d.ts +70 -0
  26. package/dist/VersionCompare/index.d.ts +3 -0
  27. package/dist/VersionCompare/index.js +11 -0
  28. package/dist/VersionCompare-UUZOPTQO.css +68 -0
  29. package/dist/chunk-73QBUUYX.js +102 -0
  30. package/dist/chunk-BVWSLXTY.js +187 -0
  31. package/dist/chunk-EZBLOUWX.js +176 -0
  32. package/dist/chunk-MUGM7SEG.js +88 -0
  33. package/dist/chunk-N4GFRW5C.js +96 -0
  34. package/dist/chunk-UO7JZVCO.js +35 -0
  35. package/dist/generated/index.d.ts +6 -0
  36. package/dist/generated/index.js +46 -40
  37. package/dist/index.js +46 -40
  38. package/dist/styles.css +473 -0
  39. package/package.json +3 -3
  40. package/dist/{chunk-RT323I4I.js → chunk-A4VMJMXJ.js} +1 -1
  41. package/dist/{chunk-PUQY4WXR.js → chunk-J2G4HGQM.js} +1 -1
  42. /package/dist/{chunk-4Z7PW3L6.js → chunk-MSSZHDZI.js} +0 -0
@@ -0,0 +1,187 @@
1
+ import { VisuallyHidden } from './chunk-BZFWDIV6.js';
2
+ import { cx } from './chunk-ODEQTPFM.js';
3
+ import './DiffView-RVLIHTKG.css';
4
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
+
6
+ var DIFF_VIEW_LABELS = {
7
+ skipped: (count) => count === 1 ? "1 unchanged line" : `${count.toLocaleString()} unchanged lines`,
8
+ added: "Added",
9
+ removed: "Removed",
10
+ region: "Line changes"
11
+ };
12
+ function DiffView({ sections, labels: overrides, className, "aria-label": ariaLabel, ...rest }) {
13
+ const labels = overrides ? { ...DIFF_VIEW_LABELS, ...overrides } : DIFF_VIEW_LABELS;
14
+ return /* @__PURE__ */ jsx("div", { ...rest, role: "group", "aria-label": ariaLabel ?? labels.region, className: cx("crewlet-diff-view", className), children: sections.map((section, s) => (
15
+ // A section has no identity of its own: a diff is computed whole, so
16
+ // its position is what tells two sections apart.
17
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-diff-view__section", children: [
18
+ section.skipped > 0 && /* @__PURE__ */ jsx("div", { className: "crewlet-diff-view__skip", children: labels.skipped(section.skipped) }),
19
+ section.lines.map((line, i) => (
20
+ // THE CLASS NAMES ARE LITERALS, never assembled from the value: a
21
+ // stylesheet gate that cannot see a class cannot tell a rule this
22
+ // file relies on from one nothing uses.
23
+ /* @__PURE__ */ jsxs(
24
+ "div",
25
+ {
26
+ className: cx(
27
+ "crewlet-diff-view__line",
28
+ line.kind === "add" && "crewlet-diff-view__line--add",
29
+ line.kind === "remove" && "crewlet-diff-view__line--remove"
30
+ ),
31
+ children: [
32
+ /* @__PURE__ */ jsx("span", { className: "crewlet-diff-view__number", "aria-hidden": "true", children: line.before ?? "" }),
33
+ /* @__PURE__ */ jsx("span", { className: "crewlet-diff-view__number", "aria-hidden": "true", children: line.after ?? "" }),
34
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-diff-view__mark", children: [
35
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: line.kind === "add" ? "+" : line.kind === "remove" ? "\u2212" : " " }),
36
+ line.kind === "add" && /* @__PURE__ */ jsx(VisuallyHidden, { children: labels.added }),
37
+ line.kind === "remove" && /* @__PURE__ */ jsx(VisuallyHidden, { children: labels.removed })
38
+ ] }),
39
+ /* @__PURE__ */ jsx("span", { className: "crewlet-diff-view__text", children: line.text || " " })
40
+ ]
41
+ },
42
+ i
43
+ )
44
+ ))
45
+ ] }, s)
46
+ )) });
47
+ }
48
+ var DIFF_SUMMARY_LABELS = {
49
+ spoken: (added, removed) => `${added === 1 ? "1 line" : `${added.toLocaleString()} lines`} added, ${removed.toLocaleString()} removed`,
50
+ against: (what) => `against ${what}`
51
+ };
52
+ function DiffSummary({ added, removed, against, labels: overrides, className, ...rest }) {
53
+ const labels = overrides ? { ...DIFF_SUMMARY_LABELS, ...overrides } : DIFF_SUMMARY_LABELS;
54
+ return /* @__PURE__ */ jsxs("p", { ...rest, className: cx("crewlet-diff-summary", className), children: [
55
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
56
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-diff-summary__added", children: [
57
+ "+",
58
+ added.toLocaleString()
59
+ ] }),
60
+ " ",
61
+ /* @__PURE__ */ jsx("span", { className: "crewlet-diff-summary__removed", children: `\u2212${removed.toLocaleString()}` })
62
+ ] }),
63
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: labels.spoken(added, removed) }),
64
+ against !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
65
+ " ",
66
+ labels.against(against)
67
+ ] })
68
+ ] });
69
+ }
70
+
71
+ // src/DiffView/diff.ts
72
+ var MAX_DIFF_LINES = 2e3;
73
+ function splitLines(text) {
74
+ const normalised = (text ?? "").replace(/\r\n?/g, "\n");
75
+ if (normalised === "") return [];
76
+ return normalised.replace(/\n$/, "").split("\n");
77
+ }
78
+ function diffLines(before, after) {
79
+ const a = splitLines(before);
80
+ const b = splitLines(after);
81
+ if (a.length > MAX_DIFF_LINES || b.length > MAX_DIFF_LINES) {
82
+ return [
83
+ ...a.map((text, i) => ({ kind: "remove", text, before: i + 1, after: null })),
84
+ ...b.map((text, i) => ({ kind: "add", text, before: null, after: i + 1 }))
85
+ ];
86
+ }
87
+ return walk(a, b, common(a, b));
88
+ }
89
+ function diffStat(diff) {
90
+ let added = 0;
91
+ let removed = 0;
92
+ for (const line of diff) {
93
+ if (line.kind === "add") added++;
94
+ if (line.kind === "remove") removed++;
95
+ }
96
+ return { added, removed, identical: added === 0 && removed === 0 };
97
+ }
98
+ function collapseDiff(diff, context = 3) {
99
+ const keep = new Array(diff.length).fill(false);
100
+ diff.forEach((line, i) => {
101
+ if (line.kind === "same") return;
102
+ for (let k = Math.max(0, i - context); k <= Math.min(diff.length - 1, i + context); k++) {
103
+ keep[k] = true;
104
+ }
105
+ });
106
+ const out = [];
107
+ let skipped = 0;
108
+ let current = null;
109
+ diff.forEach((line, i) => {
110
+ if (keep[i]) {
111
+ if (!current) {
112
+ current = [];
113
+ out.push({ lines: current, skipped });
114
+ skipped = 0;
115
+ }
116
+ current.push(line);
117
+ return;
118
+ }
119
+ skipped++;
120
+ current = null;
121
+ });
122
+ return out;
123
+ }
124
+ function firstChangedLines(sections, max) {
125
+ const out = [];
126
+ let shown = 0;
127
+ let more = 0;
128
+ for (const section of sections) {
129
+ const kept = [];
130
+ for (const line of section.lines) {
131
+ const changed = line.kind !== "same";
132
+ if (shown >= max) {
133
+ if (changed) more++;
134
+ continue;
135
+ }
136
+ if (changed) shown++;
137
+ kept.push(line);
138
+ }
139
+ if (kept.length > 0) out.push({ lines: kept, skipped: section.skipped });
140
+ }
141
+ return { sections: out, more };
142
+ }
143
+ function common(a, b) {
144
+ const table = [];
145
+ for (let i = 0; i <= a.length; i++) table.push(new Uint32Array(b.length + 1));
146
+ for (let i = a.length - 1; i >= 0; i--) {
147
+ const row = table[i];
148
+ const next = table[i + 1];
149
+ for (let j = b.length - 1; j >= 0; j--) {
150
+ row[j] = a[i] === b[j] ? next[j + 1] + 1 : Math.max(next[j], row[j + 1]);
151
+ }
152
+ }
153
+ return table;
154
+ }
155
+ function walk(a, b, table) {
156
+ const out = [];
157
+ let i = 0;
158
+ let j = 0;
159
+ while (i < a.length && j < b.length) {
160
+ if (a[i] === b[j]) {
161
+ out.push({ kind: "same", text: a[i], before: i + 1, after: j + 1 });
162
+ i++;
163
+ j++;
164
+ continue;
165
+ }
166
+ const down = table[i + 1][j];
167
+ const right = table[i][j + 1];
168
+ if (down >= right) {
169
+ out.push({ kind: "remove", text: a[i], before: i + 1, after: null });
170
+ i++;
171
+ } else {
172
+ out.push({ kind: "add", text: b[j], before: null, after: j + 1 });
173
+ j++;
174
+ }
175
+ }
176
+ while (i < a.length) {
177
+ out.push({ kind: "remove", text: a[i], before: i + 1, after: null });
178
+ i++;
179
+ }
180
+ while (j < b.length) {
181
+ out.push({ kind: "add", text: b[j], before: null, after: j + 1 });
182
+ j++;
183
+ }
184
+ return out;
185
+ }
186
+
187
+ export { DIFF_SUMMARY_LABELS, DIFF_VIEW_LABELS, DiffSummary, DiffView, MAX_DIFF_LINES, collapseDiff, diffLines, diffStat, firstChangedLines, splitLines };
@@ -0,0 +1,176 @@
1
+ import { Document } from './chunk-WI6K5M5X.js';
2
+ import { Composer } from './chunk-VJLYGPPE.js';
3
+ import { Button } from './chunk-OG6CL3EB.js';
4
+ import { PrincipalAvatar } from './chunk-4KP4RC3O.js';
5
+ import { toInstant, RelativeTime, formatExact, toISO } from './chunk-3CZ7XAVY.js';
6
+ import { useHeadingLevel, headingTag } from './chunk-PQADV6P6.js';
7
+ import { Count } from './chunk-BHHIIK3M.js';
8
+ import { IconButton } from './chunk-4FQT6ZAY.js';
9
+ import { cx } from './chunk-ODEQTPFM.js';
10
+ import './CommentThread-7VXOFTZO.css';
11
+ import { useState, useRef, useId, useMemo } from 'react';
12
+ import { MessageSquareGlyph, XGlyph } from '@crewlethq/icons/glyphs';
13
+ import { jsxs, jsx } from 'react/jsx-runtime';
14
+
15
+ var COMMENT_THREAD_LABELS = {
16
+ heading: "Comments",
17
+ empty: "Nobody has commented.",
18
+ system: "System",
19
+ edited: "(edited)",
20
+ inReplyTo: (name) => `in reply to ${name}`,
21
+ replyTo: (name) => `Reply to ${name}`,
22
+ reply: "Reply",
23
+ replying: (name) => `Replying to ${name}`,
24
+ stopReplying: "Stop replying",
25
+ field: (subject, replyingTo) => replyingTo !== void 0 ? `Reply to ${replyingTo}` : subject !== void 0 ? `Comment on \u201C${subject}\u201D` : "Write a comment",
26
+ placeholder: "Write a comment",
27
+ submit: "Comment",
28
+ submitReply: "Reply",
29
+ emptyDraft: "Write the comment first."
30
+ };
31
+ function CommentThread({
32
+ comments,
33
+ subject,
34
+ onSubmit,
35
+ disabledReason,
36
+ busy = false,
37
+ hint,
38
+ notice,
39
+ heading = true,
40
+ now,
41
+ labels: overrides,
42
+ className
43
+ }) {
44
+ const labels = overrides ? { ...COMMENT_THREAD_LABELS, ...overrides } : COMMENT_THREAD_LABELS;
45
+ const [draft, setDraft] = useState("");
46
+ const [replyTo, setReplyTo] = useState(null);
47
+ const [sending, setSending] = useState(false);
48
+ const field = useRef(null);
49
+ const headingID = useId();
50
+ const level = useHeadingLevel();
51
+ const Heading = headingTag(level);
52
+ const byID = useMemo(() => new Map(comments.map((comment) => [comment.id, comment])), [comments]);
53
+ const nameOf = (comment) => comment.author?.name ?? labels.system;
54
+ const body = draft.trim();
55
+ const pending = busy || sending;
56
+ const reason = disabledReason ?? (body === "" ? labels.emptyDraft : void 0);
57
+ const blocked = pending || reason !== void 0;
58
+ const send = async () => {
59
+ if (!onSubmit || blocked) return;
60
+ setSending(true);
61
+ try {
62
+ const result = await onSubmit(body, replyTo);
63
+ if (result !== false) {
64
+ setDraft("");
65
+ setReplyTo(null);
66
+ }
67
+ } finally {
68
+ setSending(false);
69
+ }
70
+ };
71
+ const startReply = (comment) => {
72
+ setReplyTo(comment);
73
+ field.current?.focus();
74
+ };
75
+ return /* @__PURE__ */ jsxs(
76
+ "section",
77
+ {
78
+ className: cx("crewlet-comment-thread", className),
79
+ "aria-labelledby": heading ? headingID : void 0,
80
+ "aria-label": heading ? void 0 : labels.heading,
81
+ children: [
82
+ heading && /* @__PURE__ */ jsxs(Heading, { className: "crewlet-comment-thread__heading", id: headingID, children: [
83
+ /* @__PURE__ */ jsx(MessageSquareGlyph, { size: "sm" }),
84
+ labels.heading,
85
+ /* @__PURE__ */ jsx(Count, { value: comments.length })
86
+ ] }),
87
+ comments.length === 0 ? /* @__PURE__ */ jsx("p", { className: "crewlet-comment-thread__empty", children: labels.empty }) : (
88
+ // The markers are off, and WebKit drops the list role with them, so
89
+ // the role is declared and the redundant-role rule silenced for that.
90
+ // eslint-disable-next-line jsx-a11y/no-redundant-roles
91
+ /* @__PURE__ */ jsx("ol", { role: "list", className: "crewlet-comment-thread__list", children: comments.map((comment) => {
92
+ const parent = comment.replyTo !== void 0 ? byID.get(comment.replyTo) : void 0;
93
+ const created = toInstant(comment.createdAt);
94
+ const edited = toInstant(comment.editedAt);
95
+ const name = nameOf(comment);
96
+ return /* @__PURE__ */ jsxs("li", { className: "crewlet-comment-thread__comment", children: [
97
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-comment-thread__head", children: [
98
+ comment.author ? /* @__PURE__ */ jsxs("span", { className: "crewlet-comment-thread__author", children: [
99
+ /* @__PURE__ */ jsx(PrincipalAvatar, { principal: comment.author, size: "xs" }),
100
+ /* @__PURE__ */ jsx("span", { className: "crewlet-comment-thread__name", children: comment.author.name })
101
+ ] }) : /* @__PURE__ */ jsx("span", { className: "crewlet-comment-thread__name", children: labels.system }),
102
+ /* @__PURE__ */ jsx(RelativeTime, { value: comment.createdAt, now, className: "crewlet-comment-thread__meta" }),
103
+ edited !== null && edited !== created && /* @__PURE__ */ jsx(
104
+ "time",
105
+ {
106
+ className: "crewlet-comment-thread__meta",
107
+ dateTime: toISO(comment.editedAt) ?? void 0,
108
+ title: formatExact(comment.editedAt) ?? void 0,
109
+ children: labels.edited
110
+ }
111
+ ),
112
+ parent && /* @__PURE__ */ jsx("span", { className: "crewlet-comment-thread__meta", children: labels.inReplyTo(nameOf(parent)) }),
113
+ onSubmit && /* @__PURE__ */ jsx(
114
+ Button,
115
+ {
116
+ size: "small",
117
+ variant: "ghost",
118
+ className: "crewlet-comment-thread__reply",
119
+ "aria-label": labels.replyTo(name),
120
+ onClick: () => startReply(comment),
121
+ children: labels.reply
122
+ }
123
+ )
124
+ ] }),
125
+ /* @__PURE__ */ jsx(Document, { size: "sm", measure: "none", children: comment.body })
126
+ ] }, comment.id);
127
+ }) })
128
+ ),
129
+ onSubmit && /* @__PURE__ */ jsxs("div", { className: "crewlet-comment-thread__compose", children: [
130
+ replyTo && /* @__PURE__ */ jsxs("span", { className: "crewlet-comment-thread__replying", children: [
131
+ labels.replying(nameOf(replyTo)),
132
+ /* @__PURE__ */ jsx(
133
+ IconButton,
134
+ {
135
+ size: "sm",
136
+ variant: "ghost",
137
+ label: labels.stopReplying,
138
+ icon: /* @__PURE__ */ jsx(XGlyph, { size: "sm" }),
139
+ onClick: () => {
140
+ setReplyTo(null);
141
+ field.current?.focus();
142
+ }
143
+ }
144
+ )
145
+ ] }),
146
+ /* @__PURE__ */ jsx(
147
+ Composer,
148
+ {
149
+ ref: field,
150
+ value: draft,
151
+ onChange: setDraft,
152
+ onSubmit: () => void send(),
153
+ label: labels.field(subject, replyTo ? nameOf(replyTo) : void 0),
154
+ placeholder: labels.placeholder,
155
+ actions: /* @__PURE__ */ jsx(
156
+ Button,
157
+ {
158
+ size: "small",
159
+ variant: "secondary",
160
+ loading: pending,
161
+ disabledReason: pending ? void 0 : reason,
162
+ onClick: () => void send(),
163
+ children: replyTo ? labels.submitReply : labels.submit
164
+ }
165
+ )
166
+ }
167
+ ),
168
+ (disabledReason ?? hint) !== void 0 && /* @__PURE__ */ jsx("p", { className: "crewlet-comment-thread__hint", children: disabledReason ?? hint }),
169
+ notice
170
+ ] })
171
+ ]
172
+ }
173
+ );
174
+ }
175
+
176
+ export { COMMENT_THREAD_LABELS, CommentThread };
@@ -0,0 +1,88 @@
1
+ import { Tag } from './chunk-GFV4LJHH.js';
2
+ import { Link } from './chunk-FBSEJO2C.js';
3
+ import { RelativeTime } from './chunk-3CZ7XAVY.js';
4
+ import { EmptyValue } from './chunk-EUCC37WY.js';
5
+ import { Avatar } from './chunk-5OM447RW.js';
6
+ import { VisuallyHidden } from './chunk-BZFWDIV6.js';
7
+ import { cx } from './chunk-ODEQTPFM.js';
8
+ import './TableCells-3VN5N2M3.css';
9
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
+
11
+ function TableKeyCell({ value, text, href, emptyLabel = "Not set" }) {
12
+ if (!value) return /* @__PURE__ */ jsx(EmptyValue, { label: emptyLabel });
13
+ if (href !== void 0) {
14
+ return /* @__PURE__ */ jsx(Link, { href, size: "inherit", className: "crewlet-table-cell__key", title: value, children: text ?? value });
15
+ }
16
+ return /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__key", title: value, children: text ?? value });
17
+ }
18
+ var groupFigure = (value) => value.toLocaleString();
19
+ function TableNumberCell({
20
+ value,
21
+ format = groupFigure,
22
+ suffix,
23
+ title,
24
+ emptyLabel = "Nothing recorded"
25
+ }) {
26
+ if (value === null || value === void 0 || !Number.isFinite(value)) return /* @__PURE__ */ jsx(EmptyValue, { label: emptyLabel });
27
+ return /* @__PURE__ */ jsxs("span", { className: "crewlet-table-cell__number", title, children: [
28
+ format(value),
29
+ suffix
30
+ ] });
31
+ }
32
+ function TableDateCell({ value, now, emptyLabel = "Never" }) {
33
+ if (value === null || value === void 0 || value === "") return /* @__PURE__ */ jsx(EmptyValue, { label: emptyLabel });
34
+ return /* @__PURE__ */ jsx(RelativeTime, { value, now, emptyLabel, className: "crewlet-table-cell__date" });
35
+ }
36
+ function TableEntityCell({
37
+ name,
38
+ kind = "agent",
39
+ badge,
40
+ href,
41
+ title,
42
+ size = "xs",
43
+ emptyLabel = "Nobody"
44
+ }) {
45
+ if (!name) return /* @__PURE__ */ jsx(EmptyValue, { label: emptyLabel });
46
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
47
+ /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__badge", "aria-hidden": "true", children: badge ?? /* @__PURE__ */ jsx(Avatar, { name, size, kind, decorative: true }) }),
48
+ /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__truncate", children: name })
49
+ ] });
50
+ if (href !== void 0) {
51
+ return /* @__PURE__ */ jsx(Link, { href, variant: "subtle", size: "inherit", className: "crewlet-table-cell__entity", title: title ?? name, children: inner });
52
+ }
53
+ return /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__entity", title: title ?? name, children: inner });
54
+ }
55
+ function TableStatusCell({ label, glyph, tone = "neutral", title }) {
56
+ return /* @__PURE__ */ jsxs("span", { className: cx("crewlet-table-cell__status", `crewlet-table-cell__status--${tone}`), title: title ?? label, children: [
57
+ /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__glyph", "aria-hidden": "true", children: glyph }),
58
+ /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__truncate", children: label })
59
+ ] });
60
+ }
61
+ var TABLE_TAGS_CELL_LABELS = {
62
+ more: (count) => count === 1 ? "1 more tag" : `${count.toLocaleString()} more tags`
63
+ };
64
+ function TableTagsCell({ tags, max = 3, emptyLabel = "No tags", labels: overrides }) {
65
+ const list = tags ?? [];
66
+ if (list.length === 0) return /* @__PURE__ */ jsx(EmptyValue, { label: emptyLabel });
67
+ const labels = overrides ? { ...TABLE_TAGS_CELL_LABELS, ...overrides } : TABLE_TAGS_CELL_LABELS;
68
+ const shown = list.slice(0, max);
69
+ const rest = list.length - shown.length;
70
+ return /* @__PURE__ */ jsxs("span", { className: "crewlet-table-cell__tags", children: [
71
+ shown.map((tag) => /* @__PURE__ */ jsx(Tag, { appearance: "outline", size: "xs", children: tag }, tag)),
72
+ rest > 0 && /* @__PURE__ */ jsxs("span", { className: "crewlet-table-cell__more", title: list.slice(max).join(", "), children: [
73
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
74
+ "+",
75
+ rest
76
+ ] }),
77
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: labels.more(rest) })
78
+ ] })
79
+ ] });
80
+ }
81
+ function TableTextCell({ children, icon, mark }) {
82
+ return /* @__PURE__ */ jsxs("span", { className: "crewlet-table-cell__text", children: [
83
+ mark ?? (icon !== void 0 && icon !== null ? /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__icon", "aria-hidden": "true", children: icon }) : null),
84
+ /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__truncate", children })
85
+ ] });
86
+ }
87
+
88
+ export { TABLE_TAGS_CELL_LABELS, TableDateCell, TableEntityCell, TableKeyCell, TableNumberCell, TableStatusCell, TableTagsCell, TableTextCell };
@@ -0,0 +1,96 @@
1
+ import { PRESENCE_LABELS, presenceOrder, collapseSessions } from './chunk-S35G6PNC.js';
2
+ import { Button } from './chunk-OG6CL3EB.js';
3
+ import { Avatar } from './chunk-5OM447RW.js';
4
+ import { headingTag, useHeadingLevel } from './chunk-PQADV6P6.js';
5
+ import { IconButton } from './chunk-4FQT6ZAY.js';
6
+ import { cx } from './chunk-ODEQTPFM.js';
7
+ import './PeopleRail-R64WVOSH.css';
8
+ import { useId } from 'react';
9
+ import { isCrewletCharacter } from '@crewlethq/icons/characters';
10
+ import { XGlyph } from '@crewlethq/icons/glyphs';
11
+ import { jsxs, jsx } from 'react/jsx-runtime';
12
+
13
+ var PEOPLE_RAIL_LABELS = {
14
+ title: "People here",
15
+ close: "Close people",
16
+ you: "You",
17
+ nobody: "Nobody else is here right now.",
18
+ follow: "Follow",
19
+ following: "Following",
20
+ followName: (name) => `Follow ${name}`,
21
+ stopFollowingName: (name) => `Stop following ${name}`,
22
+ activity: PRESENCE_LABELS.activity
23
+ };
24
+ function peopleRailKey(member) {
25
+ return member.seat ?? member.id;
26
+ }
27
+ function PeopleRail({
28
+ members,
29
+ self,
30
+ following,
31
+ onFollow,
32
+ onClose,
33
+ actions,
34
+ labels: overrides,
35
+ className
36
+ }) {
37
+ const labels = overrides ? { ...PEOPLE_RAIL_LABELS, ...overrides } : PEOPLE_RAIL_LABELS;
38
+ const headingID = useId();
39
+ const Heading = headingTag(useHeadingLevel());
40
+ const others = presenceOrder(collapseSessions(members));
41
+ return /* @__PURE__ */ jsxs("aside", { className: cx("crewlet-people-rail", className), "aria-labelledby": headingID, children: [
42
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-people-rail__head", children: [
43
+ /* @__PURE__ */ jsx(Heading, { className: "crewlet-people-rail__title", id: headingID, children: labels.title }),
44
+ onClose && /* @__PURE__ */ jsx(IconButton, { size: "sm", variant: "ghost", label: labels.close, icon: /* @__PURE__ */ jsx(XGlyph, { size: "sm" }), onClick: onClose })
45
+ ] }),
46
+ /* @__PURE__ */ jsxs("ul", { role: "list", className: "crewlet-people-rail__list", children: [
47
+ self && /* @__PURE__ */ jsxs("li", { className: "crewlet-people-rail__person", children: [
48
+ /* @__PURE__ */ jsx(PresenceBadge, { member: self }),
49
+ /* @__PURE__ */ jsx("span", { className: "crewlet-people-rail__text", children: /* @__PURE__ */ jsx("span", { className: "crewlet-people-rail__name", children: labels.you }) })
50
+ ] }),
51
+ others.map((member) => {
52
+ const key = peopleRailKey(member);
53
+ const followed = following !== void 0 && following === key;
54
+ const extra = actions?.(member);
55
+ return /* @__PURE__ */ jsxs("li", { className: "crewlet-people-rail__person", children: [
56
+ /* @__PURE__ */ jsx(PresenceBadge, { member }),
57
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-people-rail__text", children: [
58
+ /* @__PURE__ */ jsx("span", { className: "crewlet-people-rail__name", children: member.name }),
59
+ /* @__PURE__ */ jsx("span", { className: "crewlet-people-rail__where", children: member.location ?? labels.activity(member.activity, member.kind) })
60
+ ] }),
61
+ extra !== void 0 && extra !== null || onFollow ? /* @__PURE__ */ jsxs("span", { className: "crewlet-people-rail__actions", children: [
62
+ extra,
63
+ onFollow && /* @__PURE__ */ jsx(
64
+ Button,
65
+ {
66
+ size: "small",
67
+ variant: followed ? "primary" : "secondary",
68
+ pressed: followed,
69
+ "aria-label": followed ? labels.stopFollowingName(member.name) : labels.followName(member.name),
70
+ onClick: () => onFollow(followed ? null : member),
71
+ children: followed ? labels.following : labels.follow
72
+ }
73
+ )
74
+ ] }) : null
75
+ ] }, key);
76
+ })
77
+ ] }),
78
+ others.length === 0 && /* @__PURE__ */ jsx("p", { className: "crewlet-people-rail__note", children: labels.nobody })
79
+ ] });
80
+ }
81
+ function PresenceBadge({ member }) {
82
+ return /* @__PURE__ */ jsx(
83
+ Avatar,
84
+ {
85
+ name: member.name,
86
+ kind: member.kind,
87
+ src: member.src,
88
+ character: member.character !== void 0 && isCrewletCharacter(member.character) ? member.character : void 0,
89
+ hue: member.kind === "agent" ? member.hue : void 0,
90
+ size: "sm",
91
+ decorative: true
92
+ }
93
+ );
94
+ }
95
+
96
+ export { PEOPLE_RAIL_LABELS, PeopleRail, peopleRailKey };
@@ -0,0 +1,35 @@
1
+ import { Button } from './chunk-OG6CL3EB.js';
2
+ import { cx } from './chunk-ODEQTPFM.js';
3
+ import './ConflictNote-DH77PYF7.css';
4
+ import { CircleAlertGlyph } from '@crewlethq/icons/glyphs';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ var CONFLICT_NOTE_LABELS = {
8
+ changedBy: (subject, name) => `${subject} was changed by ${name} since you opened it. Look again, then retry.`,
9
+ changed: (subject) => `${subject} was changed since you opened it. Look again, then retry.`,
10
+ dismiss: "Dismiss"
11
+ };
12
+ function ConflictNote({
13
+ subject,
14
+ changedBy,
15
+ message,
16
+ onDismiss,
17
+ actions,
18
+ labels: overrides,
19
+ className,
20
+ ...rest
21
+ }) {
22
+ const labels = overrides ? { ...CONFLICT_NOTE_LABELS, ...overrides } : CONFLICT_NOTE_LABELS;
23
+ const named = changedBy !== void 0 && changedBy !== "";
24
+ const sentence = named ? labels.changedBy(subject, changedBy) : message ?? labels.changed(subject);
25
+ return /* @__PURE__ */ jsxs("div", { ...rest, role: "alert", className: cx("crewlet-conflict-note", className), children: [
26
+ /* @__PURE__ */ jsx(CircleAlertGlyph, { size: "sm", className: "crewlet-conflict-note__glyph" }),
27
+ /* @__PURE__ */ jsx("span", { className: "crewlet-conflict-note__text", children: sentence }),
28
+ (actions !== void 0 || onDismiss) && /* @__PURE__ */ jsxs("span", { className: "crewlet-conflict-note__actions", children: [
29
+ actions,
30
+ onDismiss && /* @__PURE__ */ jsx(Button, { size: "small", variant: "ghost", onClick: onDismiss, children: labels.dismiss })
31
+ ] })
32
+ ] });
33
+ }
34
+
35
+ export { CONFLICT_NOTE_LABELS, ConflictNote };
@@ -27,8 +27,10 @@ export * from '../ChoiceList/index.js';
27
27
  export * from '../CodeBlock/index.js';
28
28
  export * from '../Combobox/index.js';
29
29
  export * from '../CommandPalette/index.js';
30
+ export * from '../CommentThread/index.js';
30
31
  export * from '../Composer/index.js';
31
32
  export * from '../ConfirmField/index.js';
33
+ export * from '../ConflictNote/index.js';
32
34
  export * from '../Container/index.js';
33
35
  export * from '../Copyable/index.js';
34
36
  export * from '../Count/index.js';
@@ -38,6 +40,7 @@ export * from '../DataView/index.js';
38
40
  export * from '../DateTimePicker/index.js';
39
41
  export * from '../DescriptionList/index.js';
40
42
  export * from '../DiffList/index.js';
43
+ export * from '../DiffView/index.js';
41
44
  export * from '../Disclosure/index.js';
42
45
  export * from '../Divider/index.js';
43
46
  export * from '../Document/index.js';
@@ -82,6 +85,7 @@ export * from '../OrgNode/index.js';
82
85
  export * from '../OrgTable/index.js';
83
86
  export * from '../Outline/index.js';
84
87
  export * from '../PageHeader/index.js';
88
+ export * from '../PeopleRail/index.js';
85
89
  export * from '../PinTile/index.js';
86
90
  export * from '../Popover/index.js';
87
91
  export * from '../PresenceModel/index.js';
@@ -114,6 +118,7 @@ export * from '../Stepper/index.js';
114
118
  export * from '../Switch/index.js';
115
119
  export * from '../Switcher/index.js';
116
120
  export * from '../Table/index.js';
121
+ export * from '../TableCells/index.js';
117
122
  export * from '../Tabs/index.js';
118
123
  export * from '../Tag/index.js';
119
124
  export * from '../TagGroup/index.js';
@@ -131,6 +136,7 @@ export * from '../Tooltip/index.js';
131
136
  export * from '../Tree/index.js';
132
137
  export * from '../TreeCanvas/index.js';
133
138
  export * from '../TreeGrid/index.js';
139
+ export * from '../VersionCompare/index.js';
134
140
  export * from '../VersionTimeline/index.js';
135
141
  export * from '../VisuallyHidden/index.js';
136
142
  export * from '../utils/index.js';