@tldraw/commenting 0.0.0-bootstrap
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/README.md +11 -0
- package/commenting.css +832 -0
- package/dist-cjs/canvas/cluster-input.js +40 -0
- package/dist-cjs/canvas/cluster-input.js.map +7 -0
- package/dist-cjs/canvas/comment-body.js +31 -0
- package/dist-cjs/canvas/comment-body.js.map +7 -0
- package/dist-cjs/canvas/comment-render.js +72 -0
- package/dist-cjs/canvas/comment-render.js.map +7 -0
- package/dist-cjs/canvas/comment-store.js +48 -0
- package/dist-cjs/canvas/comment-store.js.map +7 -0
- package/dist-cjs/canvas/comment-tool.js +160 -0
- package/dist-cjs/canvas/comment-tool.js.map +7 -0
- package/dist-cjs/canvas/comments-filter-menu.js +109 -0
- package/dist-cjs/canvas/comments-filter-menu.js.map +7 -0
- package/dist-cjs/canvas/comments-menu-item.js +42 -0
- package/dist-cjs/canvas/comments-menu-item.js.map +7 -0
- package/dist-cjs/canvas/comments-overflow-menu.js +64 -0
- package/dist-cjs/canvas/comments-overflow-menu.js.map +7 -0
- package/dist-cjs/canvas/comments-overlay.js +1081 -0
- package/dist-cjs/canvas/comments-overlay.js.map +7 -0
- package/dist-cjs/canvas/comments-sidebar.js +134 -0
- package/dist-cjs/canvas/comments-sidebar.js.map +7 -0
- package/dist-cjs/canvas/hooks.js +45 -0
- package/dist-cjs/canvas/hooks.js.map +7 -0
- package/dist-cjs/canvas/license.js +28 -0
- package/dist-cjs/canvas/license.js.map +7 -0
- package/dist-cjs/canvas/options.js +45 -0
- package/dist-cjs/canvas/options.js.map +7 -0
- package/dist-cjs/canvas/region-options.js +49 -0
- package/dist-cjs/canvas/region-options.js.map +7 -0
- package/dist-cjs/canvas/rich-text.js +28 -0
- package/dist-cjs/canvas/rich-text.js.map +7 -0
- package/dist-cjs/canvas/sidebar-filters.js +30 -0
- package/dist-cjs/canvas/sidebar-filters.js.map +7 -0
- package/dist-cjs/canvas/state.js +76 -0
- package/dist-cjs/canvas/state.js.map +7 -0
- package/dist-cjs/canvas/thread-state.js +81 -0
- package/dist-cjs/canvas/thread-state.js.map +7 -0
- package/dist-cjs/clustering/computeClusterTable.js +83 -0
- package/dist-cjs/clustering/computeClusterTable.js.map +7 -0
- package/dist-cjs/clustering/mst.js +117 -0
- package/dist-cjs/clustering/mst.js.map +7 -0
- package/dist-cjs/clustering/replay.js +275 -0
- package/dist-cjs/clustering/replay.js.map +7 -0
- package/dist-cjs/clustering/runtime.js +134 -0
- package/dist-cjs/clustering/runtime.js.map +7 -0
- package/dist-cjs/clustering/schedule.js +170 -0
- package/dist-cjs/clustering/schedule.js.map +7 -0
- package/dist-cjs/clustering/types.js +17 -0
- package/dist-cjs/clustering/types.js.map +7 -0
- package/dist-cjs/index.d.ts +868 -0
- package/dist-cjs/index.js +126 -0
- package/dist-cjs/index.js.map +7 -0
- package/dist-cjs/ui/avatar.js +43 -0
- package/dist-cjs/ui/avatar.js.map +7 -0
- package/dist-cjs/ui/byline.js +35 -0
- package/dist-cjs/ui/byline.js.map +7 -0
- package/dist-cjs/ui/comment-card.js +37 -0
- package/dist-cjs/ui/comment-card.js.map +7 -0
- package/dist-cjs/ui/comment-composer.js +136 -0
- package/dist-cjs/ui/comment-composer.js.map +7 -0
- package/dist-cjs/ui/comment-extensions.js +37 -0
- package/dist-cjs/ui/comment-extensions.js.map +7 -0
- package/dist-cjs/ui/comment-mention.js +42 -0
- package/dist-cjs/ui/comment-mention.js.map +7 -0
- package/dist-cjs/ui/comment-pin.js +29 -0
- package/dist-cjs/ui/comment-pin.js.map +7 -0
- package/dist-cjs/ui/comment-text.js +29 -0
- package/dist-cjs/ui/comment-text.js.map +7 -0
- package/dist-cjs/ui/comment-thread.js +45 -0
- package/dist-cjs/ui/comment-thread.js.map +7 -0
- package/dist-cjs/ui/comments-list.js +106 -0
- package/dist-cjs/ui/comments-list.js.map +7 -0
- package/dist-cjs/ui/count-badge.js +28 -0
- package/dist-cjs/ui/count-badge.js.map +7 -0
- package/dist-cjs/ui/empty-state.js +31 -0
- package/dist-cjs/ui/empty-state.js.map +7 -0
- package/dist-cjs/ui/format-time.js +46 -0
- package/dist-cjs/ui/format-time.js.map +7 -0
- package/dist-cjs/ui/mention-list.js +70 -0
- package/dist-cjs/ui/mention-list.js.map +7 -0
- package/dist-cjs/ui/mention-suggestion.js +206 -0
- package/dist-cjs/ui/mention-suggestion.js.map +7 -0
- package/dist-cjs/ui/mention.js +31 -0
- package/dist-cjs/ui/mention.js.map +7 -0
- package/dist-cjs/ui/reaction.js +31 -0
- package/dist-cjs/ui/reaction.js.map +7 -0
- package/dist-cjs/ui/reactions.js +34 -0
- package/dist-cjs/ui/reactions.js.map +7 -0
- package/dist-cjs/ui/render-markdown.js +63 -0
- package/dist-cjs/ui/render-markdown.js.map +7 -0
- package/dist-cjs/ui/send-button.js +28 -0
- package/dist-cjs/ui/send-button.js.map +7 -0
- package/dist-esm/canvas/cluster-input.mjs +20 -0
- package/dist-esm/canvas/cluster-input.mjs.map +7 -0
- package/dist-esm/canvas/comment-body.mjs +11 -0
- package/dist-esm/canvas/comment-body.mjs.map +7 -0
- package/dist-esm/canvas/comment-render.mjs +52 -0
- package/dist-esm/canvas/comment-render.mjs.map +7 -0
- package/dist-esm/canvas/comment-store.mjs +28 -0
- package/dist-esm/canvas/comment-store.mjs.map +7 -0
- package/dist-esm/canvas/comment-tool.mjs +142 -0
- package/dist-esm/canvas/comment-tool.mjs.map +7 -0
- package/dist-esm/canvas/comments-filter-menu.mjs +99 -0
- package/dist-esm/canvas/comments-filter-menu.mjs.map +7 -0
- package/dist-esm/canvas/comments-menu-item.mjs +22 -0
- package/dist-esm/canvas/comments-menu-item.mjs.map +7 -0
- package/dist-esm/canvas/comments-overflow-menu.mjs +53 -0
- package/dist-esm/canvas/comments-overflow-menu.mjs.map +7 -0
- package/dist-esm/canvas/comments-overlay.mjs +1094 -0
- package/dist-esm/canvas/comments-overlay.mjs.map +7 -0
- package/dist-esm/canvas/comments-sidebar.mjs +120 -0
- package/dist-esm/canvas/comments-sidebar.mjs.map +7 -0
- package/dist-esm/canvas/hooks.mjs +25 -0
- package/dist-esm/canvas/hooks.mjs.map +7 -0
- package/dist-esm/canvas/license.mjs +8 -0
- package/dist-esm/canvas/license.mjs.map +7 -0
- package/dist-esm/canvas/options.mjs +27 -0
- package/dist-esm/canvas/options.mjs.map +7 -0
- package/dist-esm/canvas/region-options.mjs +29 -0
- package/dist-esm/canvas/region-options.mjs.map +7 -0
- package/dist-esm/canvas/rich-text.mjs +8 -0
- package/dist-esm/canvas/rich-text.mjs.map +7 -0
- package/dist-esm/canvas/sidebar-filters.mjs +10 -0
- package/dist-esm/canvas/sidebar-filters.mjs.map +7 -0
- package/dist-esm/canvas/state.mjs +60 -0
- package/dist-esm/canvas/state.mjs.map +7 -0
- package/dist-esm/canvas/thread-state.mjs +61 -0
- package/dist-esm/canvas/thread-state.mjs.map +7 -0
- package/dist-esm/clustering/computeClusterTable.mjs +63 -0
- package/dist-esm/clustering/computeClusterTable.mjs.map +7 -0
- package/dist-esm/clustering/mst.mjs +97 -0
- package/dist-esm/clustering/mst.mjs.map +7 -0
- package/dist-esm/clustering/replay.mjs +255 -0
- package/dist-esm/clustering/replay.mjs.map +7 -0
- package/dist-esm/clustering/runtime.mjs +114 -0
- package/dist-esm/clustering/runtime.mjs.map +7 -0
- package/dist-esm/clustering/schedule.mjs +150 -0
- package/dist-esm/clustering/schedule.mjs.map +7 -0
- package/dist-esm/clustering/types.mjs +1 -0
- package/dist-esm/clustering/types.mjs.map +7 -0
- package/dist-esm/index.d.mts +868 -0
- package/dist-esm/index.mjs +139 -0
- package/dist-esm/index.mjs.map +7 -0
- package/dist-esm/ui/avatar.mjs +23 -0
- package/dist-esm/ui/avatar.mjs.map +7 -0
- package/dist-esm/ui/byline.mjs +15 -0
- package/dist-esm/ui/byline.mjs.map +7 -0
- package/dist-esm/ui/comment-card.mjs +17 -0
- package/dist-esm/ui/comment-card.mjs.map +7 -0
- package/dist-esm/ui/comment-composer.mjs +116 -0
- package/dist-esm/ui/comment-composer.mjs.map +7 -0
- package/dist-esm/ui/comment-extensions.mjs +17 -0
- package/dist-esm/ui/comment-extensions.mjs.map +7 -0
- package/dist-esm/ui/comment-mention.mjs +22 -0
- package/dist-esm/ui/comment-mention.mjs.map +7 -0
- package/dist-esm/ui/comment-pin.mjs +9 -0
- package/dist-esm/ui/comment-pin.mjs.map +7 -0
- package/dist-esm/ui/comment-text.mjs +9 -0
- package/dist-esm/ui/comment-text.mjs.map +7 -0
- package/dist-esm/ui/comment-thread.mjs +25 -0
- package/dist-esm/ui/comment-thread.mjs.map +7 -0
- package/dist-esm/ui/comments-list.mjs +86 -0
- package/dist-esm/ui/comments-list.mjs.map +7 -0
- package/dist-esm/ui/count-badge.mjs +8 -0
- package/dist-esm/ui/count-badge.mjs.map +7 -0
- package/dist-esm/ui/empty-state.mjs +11 -0
- package/dist-esm/ui/empty-state.mjs.map +7 -0
- package/dist-esm/ui/format-time.mjs +26 -0
- package/dist-esm/ui/format-time.mjs.map +7 -0
- package/dist-esm/ui/mention-list.mjs +50 -0
- package/dist-esm/ui/mention-list.mjs.map +7 -0
- package/dist-esm/ui/mention-suggestion.mjs +186 -0
- package/dist-esm/ui/mention-suggestion.mjs.map +7 -0
- package/dist-esm/ui/mention.mjs +11 -0
- package/dist-esm/ui/mention.mjs.map +7 -0
- package/dist-esm/ui/reaction.mjs +11 -0
- package/dist-esm/ui/reaction.mjs.map +7 -0
- package/dist-esm/ui/reactions.mjs +14 -0
- package/dist-esm/ui/reactions.mjs.map +7 -0
- package/dist-esm/ui/render-markdown.mjs +45 -0
- package/dist-esm/ui/render-markdown.mjs.map +7 -0
- package/dist-esm/ui/send-button.mjs +8 -0
- package/dist-esm/ui/send-button.mjs.map +7 -0
- package/package.json +71 -0
- package/src/canvas/canvas.css +148 -0
- package/src/canvas/cluster-input.test.ts +223 -0
- package/src/canvas/cluster-input.ts +29 -0
- package/src/canvas/comment-body.tsx +21 -0
- package/src/canvas/comment-render.test.ts +90 -0
- package/src/canvas/comment-render.ts +92 -0
- package/src/canvas/comment-store.ts +55 -0
- package/src/canvas/comment-tool.tsx +200 -0
- package/src/canvas/comments-filter-menu.tsx +104 -0
- package/src/canvas/comments-menu-item.tsx +24 -0
- package/src/canvas/comments-overflow-menu.tsx +62 -0
- package/src/canvas/comments-overlay.tsx +1460 -0
- package/src/canvas/comments-sidebar.tsx +184 -0
- package/src/canvas/hooks.ts +28 -0
- package/src/canvas/license.ts +15 -0
- package/src/canvas/options.test.ts +127 -0
- package/src/canvas/options.ts +111 -0
- package/src/canvas/region-options.ts +57 -0
- package/src/canvas/rich-text.ts +15 -0
- package/src/canvas/sidebar-filters.ts +25 -0
- package/src/canvas/state.ts +102 -0
- package/src/canvas/thread-state.ts +91 -0
- package/src/clustering/computeClusterTable.test.ts +299 -0
- package/src/clustering/computeClusterTable.ts +82 -0
- package/src/clustering/locality.test.ts +189 -0
- package/src/clustering/mst.test.ts +383 -0
- package/src/clustering/mst.ts +134 -0
- package/src/clustering/replay.test.ts +547 -0
- package/src/clustering/replay.ts +326 -0
- package/src/clustering/runtime.test.ts +596 -0
- package/src/clustering/runtime.ts +153 -0
- package/src/clustering/schedule.test.ts +514 -0
- package/src/clustering/schedule.ts +184 -0
- package/src/clustering/types.ts +102 -0
- package/src/index.ts +96 -0
- package/src/ui/avatar.tsx +31 -0
- package/src/ui/byline.tsx +23 -0
- package/src/ui/comment-card.tsx +32 -0
- package/src/ui/comment-composer.tsx +179 -0
- package/src/ui/comment-extensions.ts +25 -0
- package/src/ui/comment-mention.ts +47 -0
- package/src/ui/comment-pin.tsx +21 -0
- package/src/ui/comment-text.tsx +12 -0
- package/src/ui/comment-thread.tsx +56 -0
- package/src/ui/comments-list.tsx +139 -0
- package/src/ui/comments.css +678 -0
- package/src/ui/count-badge.tsx +9 -0
- package/src/ui/empty-state.tsx +16 -0
- package/src/ui/format-time.ts +29 -0
- package/src/ui/mention-list.tsx +106 -0
- package/src/ui/mention-suggestion.test.ts +18 -0
- package/src/ui/mention-suggestion.tsx +285 -0
- package/src/ui/mention.tsx +9 -0
- package/src/ui/reaction.tsx +16 -0
- package/src/ui/reactions.tsx +15 -0
- package/src/ui/render-markdown.tsx +72 -0
- package/src/ui/send-button.tsx +15 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { mergeAttributes } from '@tiptap/core'
|
|
2
|
+
import { Mention, type MentionNodeAttrs, type MentionOptions } from '@tiptap/extension-mention'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A mention node's display name: the member's current name, resolved live from its id when a
|
|
6
|
+
* resolver is given (so a rename shows through), falling back to the label captured at insert time
|
|
7
|
+
* when no source can name the id — e.g. a deleted account. The stored id is always the source of
|
|
8
|
+
* truth; live resolution only freshens the displayed name over that captured label.
|
|
9
|
+
*/
|
|
10
|
+
function mentionName(
|
|
11
|
+
attrs: MentionNodeAttrs,
|
|
12
|
+
resolveName?: (id: string) => string | undefined
|
|
13
|
+
): string {
|
|
14
|
+
const resolved = attrs.id && resolveName ? resolveName(attrs.id) : undefined
|
|
15
|
+
return resolved ?? attrs.label ?? attrs.id ?? ''
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CommentMentionOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a member id to its current display name — for the read-only render paths. Returns
|
|
21
|
+
* `undefined` when the id can't be resolved, so the render falls back to the mention's stored label.
|
|
22
|
+
*/
|
|
23
|
+
resolveName?(id: string): string | undefined
|
|
24
|
+
/** The `@`-picker suggestion config — for the composer (omit on the render paths). */
|
|
25
|
+
suggestion?: MentionOptions['suggestion']
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The comment @-mention node — TipTap's `Mention` configured to render as a `.cmt-mention` pill.
|
|
30
|
+
*
|
|
31
|
+
* A factory rather than a shared constant because it's configured differently per context: the
|
|
32
|
+
* read-only render paths pass `resolveName` (so the stored `{ id }` node always shows the member's
|
|
33
|
+
* current name, not a copy frozen at insert time), while the composer passes a `suggestion` (the
|
|
34
|
+
* `@` picker). The node schema is identical either way — only these two levers differ.
|
|
35
|
+
*/
|
|
36
|
+
export function commentMention({ resolveName, suggestion }: CommentMentionOptions = {}) {
|
|
37
|
+
return Mention.configure({
|
|
38
|
+
HTMLAttributes: { class: 'cmt-mention' },
|
|
39
|
+
renderText: ({ node }) => `@${mentionName(node.attrs as MentionNodeAttrs, resolveName)}`,
|
|
40
|
+
renderHTML: ({ node, options }) => [
|
|
41
|
+
'span',
|
|
42
|
+
mergeAttributes(options.HTMLAttributes, { 'data-mention-id': node.attrs.id }),
|
|
43
|
+
`@${mentionName(node.attrs as MentionNodeAttrs, resolveName)}`,
|
|
44
|
+
],
|
|
45
|
+
...(suggestion ? { suggestion } : {}),
|
|
46
|
+
})
|
|
47
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
/** @public */
|
|
4
|
+
export interface CommentPinProps {
|
|
5
|
+
/** What the pin shows when unresolved — a number, an author initial, an <Avatar>, etc.
|
|
6
|
+
* Left as a lever so consumers aren't locked into a count. */
|
|
7
|
+
children?: ReactNode
|
|
8
|
+
resolved?: boolean
|
|
9
|
+
/** The pin's thread is open — shows the active/selected indicator state. */
|
|
10
|
+
open?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** A canvas comment marker: shows its `children` (or a check when resolved). Purely
|
|
14
|
+
* presentational — it reflects open/resolved state via CSS; wrap it to make it clickable.
|
|
15
|
+
* @public @react */
|
|
16
|
+
export function CommentPin({ children, resolved, open }: CommentPinProps) {
|
|
17
|
+
const className = ['cmt-pin', resolved && 'cmt-pin--resolved', open && 'cmt-pin--open']
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.join(' ')
|
|
20
|
+
return <div className={className}>{resolved ? '✓' : children}</div>
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { renderMarkdown } from './render-markdown'
|
|
2
|
+
|
|
3
|
+
/** @public */
|
|
4
|
+
export interface CommentTextProps {
|
|
5
|
+
/** Rich text body, authored as markdown. */
|
|
6
|
+
text: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** A comment's body, rendered as markdown (bold, italic, code, links, lists). @public @react */
|
|
10
|
+
export function CommentText({ text }: CommentTextProps) {
|
|
11
|
+
return <div className="cmt-text">{renderMarkdown(text)}</div>
|
|
12
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
import { CommentCard, CommentCardProps } from './comment-card'
|
|
3
|
+
import { CommentComposer, CommentComposerProps } from './comment-composer'
|
|
4
|
+
|
|
5
|
+
/** @public */
|
|
6
|
+
export interface CommentThreadProps {
|
|
7
|
+
/** The thread's comments, already adapted to card props (oldest first). */
|
|
8
|
+
comments: CommentCardProps[]
|
|
9
|
+
/** Optional header, e.g. "Thread". Omit for no header. */
|
|
10
|
+
header?: ReactNode
|
|
11
|
+
/** Action controls shown at the right of the header (resolve, delete, dismiss…). */
|
|
12
|
+
headerActions?: ReactNode
|
|
13
|
+
/** When set, shows a banner above the comments (e.g. "Resolved by Jess"). */
|
|
14
|
+
resolvedBanner?: ReactNode
|
|
15
|
+
/** Reply composer props. Omit for a read-only thread (no composer). */
|
|
16
|
+
composer?: CommentComposerProps
|
|
17
|
+
/** Override how each comment renders. Defaults to `<CommentCard>`. */
|
|
18
|
+
renderComment?(comment: CommentCardProps, index: number): ReactNode
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A comment thread: an optional header, an optional resolved banner, the comments, and an
|
|
23
|
+
* optional reply composer. Presentational — you supply the comments (as card props) and the
|
|
24
|
+
* composer's handlers; how each comment renders is overridable via `renderComment`.
|
|
25
|
+
* @public @react
|
|
26
|
+
*/
|
|
27
|
+
export function CommentThread({
|
|
28
|
+
comments,
|
|
29
|
+
header,
|
|
30
|
+
headerActions,
|
|
31
|
+
resolvedBanner,
|
|
32
|
+
composer,
|
|
33
|
+
renderComment,
|
|
34
|
+
}: CommentThreadProps) {
|
|
35
|
+
return (
|
|
36
|
+
<div className="cmt-thread">
|
|
37
|
+
{(header !== undefined || headerActions !== undefined) && (
|
|
38
|
+
<div className="cmt-thread__header">
|
|
39
|
+
<span className="cmt-thread__title">{header}</span>
|
|
40
|
+
{headerActions !== undefined && (
|
|
41
|
+
<div className="cmt-thread__actions">{headerActions}</div>
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
{resolvedBanner !== undefined && <div className="cmt-thread__resolved">{resolvedBanner}</div>}
|
|
46
|
+
<div className="cmt-thread__list">
|
|
47
|
+
{comments.map((comment, i) => (
|
|
48
|
+
<div key={i}>
|
|
49
|
+
{renderComment ? renderComment(comment, i) : <CommentCard {...comment} />}
|
|
50
|
+
</div>
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
{composer !== undefined && <CommentComposer {...composer} />}
|
|
54
|
+
</div>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
import { Avatar } from './avatar'
|
|
3
|
+
import { Byline } from './byline'
|
|
4
|
+
|
|
5
|
+
/** @public */
|
|
6
|
+
export interface CommentListItemProps {
|
|
7
|
+
id: string
|
|
8
|
+
author: string
|
|
9
|
+
/** A short preview of the thread — e.g. the first comment's body. */
|
|
10
|
+
preview: ReactNode
|
|
11
|
+
/** ISO datetime of the thread's first comment. */
|
|
12
|
+
date: string
|
|
13
|
+
resolved?: boolean
|
|
14
|
+
/** Name of the page the thread lives on, shown as a small label. Omit to hide. */
|
|
15
|
+
page?: string
|
|
16
|
+
/** Total comments in the thread. */
|
|
17
|
+
count?: number
|
|
18
|
+
/** Whether this thread is the open one. */
|
|
19
|
+
selected?: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** @public */
|
|
23
|
+
export interface CommentsListProps {
|
|
24
|
+
items: CommentListItemProps[]
|
|
25
|
+
/** Called with a thread id when an item is chosen. */
|
|
26
|
+
onSelect?(id: string): void
|
|
27
|
+
/** Shown above the list (e.g. "Comments"). Omit for none. */
|
|
28
|
+
header?: ReactNode
|
|
29
|
+
/** Rendered at the right of the header row — e.g. a filter menu. */
|
|
30
|
+
headerAction?: ReactNode
|
|
31
|
+
/** Shown in place of the list when there are no threads. */
|
|
32
|
+
empty?: ReactNode
|
|
33
|
+
/** Label for a resolved thread's marker on its row. Defaults to "Resolved". */
|
|
34
|
+
resolvedLabel?: string
|
|
35
|
+
/** Override how each item renders. Defaults to `<CommentListItem>`. */
|
|
36
|
+
renderItem?(item: CommentListItemProps): ReactNode
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A scrollable list of comment threads — each an avatar, byline, and a one-line preview.
|
|
41
|
+
* Presentational: you supply the items (already summarised) and an `onSelect` handler; the canvas
|
|
42
|
+
* `CanvasCommentsSidebar` wires it to the store, but a consumer can build their own list from this.
|
|
43
|
+
* @public @react
|
|
44
|
+
*/
|
|
45
|
+
export function CommentsList({
|
|
46
|
+
items,
|
|
47
|
+
onSelect,
|
|
48
|
+
header,
|
|
49
|
+
headerAction,
|
|
50
|
+
empty,
|
|
51
|
+
resolvedLabel,
|
|
52
|
+
renderItem,
|
|
53
|
+
}: CommentsListProps) {
|
|
54
|
+
return (
|
|
55
|
+
<div className="cmt-list">
|
|
56
|
+
{(header !== undefined || headerAction) && (
|
|
57
|
+
<div className="cmt-list__header">
|
|
58
|
+
{header !== undefined && <span className="cmt-list__header-title">{header}</span>}
|
|
59
|
+
{headerAction}
|
|
60
|
+
</div>
|
|
61
|
+
)}
|
|
62
|
+
{items.length === 0 ? (
|
|
63
|
+
<div className="cmt-list__empty">{empty}</div>
|
|
64
|
+
) : (
|
|
65
|
+
<div className="cmt-list__items">
|
|
66
|
+
{items.map((item) =>
|
|
67
|
+
renderItem ? (
|
|
68
|
+
renderItem(item)
|
|
69
|
+
) : (
|
|
70
|
+
<CommentListItem
|
|
71
|
+
key={item.id}
|
|
72
|
+
{...item}
|
|
73
|
+
resolvedLabel={resolvedLabel}
|
|
74
|
+
onSelect={onSelect}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
)}
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function CommentListItem({
|
|
85
|
+
id,
|
|
86
|
+
author,
|
|
87
|
+
preview,
|
|
88
|
+
date,
|
|
89
|
+
resolved,
|
|
90
|
+
page,
|
|
91
|
+
count,
|
|
92
|
+
selected,
|
|
93
|
+
resolvedLabel = 'Resolved',
|
|
94
|
+
onSelect,
|
|
95
|
+
}: CommentListItemProps & { resolvedLabel?: string; onSelect?(id: string): void }) {
|
|
96
|
+
const handleClick = () => {
|
|
97
|
+
if (onSelect) onSelect(id)
|
|
98
|
+
}
|
|
99
|
+
return (
|
|
100
|
+
<button
|
|
101
|
+
type="button"
|
|
102
|
+
className={selected ? 'cmt-list__item cmt-list__item--selected' : 'cmt-list__item'}
|
|
103
|
+
data-resolved={resolved || undefined}
|
|
104
|
+
onClick={handleClick}
|
|
105
|
+
>
|
|
106
|
+
<Avatar name={author} />
|
|
107
|
+
<div className="cmt-list__item-body">
|
|
108
|
+
<Byline author={author} date={date} />
|
|
109
|
+
<div className="cmt-list__item-preview">{preview}</div>
|
|
110
|
+
{(resolved || page !== undefined) && (
|
|
111
|
+
<div className="cmt-list__item-meta">
|
|
112
|
+
{resolved && (
|
|
113
|
+
<span className="cmt-list__item-resolved">
|
|
114
|
+
<CheckIcon />
|
|
115
|
+
{resolvedLabel}
|
|
116
|
+
</span>
|
|
117
|
+
)}
|
|
118
|
+
{page !== undefined && <span className="cmt-list__item-page">{page}</span>}
|
|
119
|
+
</div>
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
{count !== undefined && count > 1 && <span className="cmt-list__item-count">{count}</span>}
|
|
123
|
+
</button>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function CheckIcon() {
|
|
128
|
+
return (
|
|
129
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
|
|
130
|
+
<path
|
|
131
|
+
d="M2.5 6.2 4.7 8.4 9.5 3.6"
|
|
132
|
+
stroke="currentColor"
|
|
133
|
+
strokeWidth="1.5"
|
|
134
|
+
strokeLinecap="round"
|
|
135
|
+
strokeLinejoin="round"
|
|
136
|
+
/>
|
|
137
|
+
</svg>
|
|
138
|
+
)
|
|
139
|
+
}
|