@agent-native/core-corpus 0.218.0 → 0.219.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +5 -3
- package/corpus/templates/community/qr/package.json +1 -1
- package/corpus/templates/content/CHANGELOG.md +5 -0
- package/corpus/templates/content/app/components/editor/CommentStack.tsx +301 -0
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +651 -149
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +19 -14
- package/corpus/templates/content/app/components/editor/block-field-comment-threads.ts +15 -0
- package/corpus/templates/content/app/components/editor/block-field-comments.tsx +5 -9
- package/corpus/templates/content/app/components/editor/comment-stacks.ts +143 -0
- package/corpus/templates/content/app/i18n-data.ts +8 -0
- package/corpus/templates/content/changelog/2026-10-22-blocks-with-several-comment-threads-fold-into-one-stack-in-t.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-opening-a-page-no-longer-saves-an-edit-again-after-another-o.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.comment.page-owned.md +8 -1
- package/corpus/templates/design/.generated/bridge/interact-links.generated.ts +8 -8
- package/corpus/templates/design/CHANGELOG.md +5 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +18 -1
- package/corpus/templates/design/app/components/design/bridge/interact-links.bridge.ts +8 -8
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +15 -13
- package/corpus/templates/design/app/i18n/en-US.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-modes.ts +15 -6
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-screen-rendering.tsx +29 -5
- package/corpus/templates/design/app/pages/design-editor/prototype-navigation-transition.ts +423 -0
- package/corpus/templates/design/app/pages/design-editor/view/single-screen-canvas.tsx +35 -9
- package/corpus/templates/design/changelog/2026-10-20-the-design-full-app-toggle-on-the-home-page-no-longer-hides-.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-prototype-links-can-play-code-authored-screen-transitions.md +6 -0
- package/corpus/templates/design/shared/motion-authored-css-import.ts +938 -7
- package/corpus/templates/design/shared/motion-html-source.ts +1689 -135
- package/corpus/templates/design/shared/motion-prototype-transition.ts +329 -0
- package/corpus/templates/design/shared/motion-react-source.ts +2154 -126
- package/corpus/templates/design/shared/motion-text-runtime-v1.fixture.txt +221 -0
- package/package.json +1 -1
package/corpus/README.md
CHANGED
|
@@ -45,9 +45,11 @@ actions do not expose, inspect the provider catalog/docs and call
|
|
|
45
45
|
endpoint, call `provider-api-request` (provider `hubspot`, e.g.
|
|
46
46
|
`/crm/v3/properties/deals`) via `provider-api-docs` **without `stageAs`**.
|
|
47
47
|
Property definitions are read-only control metadata, not analysis rows; never
|
|
48
|
-
stage them. `stageAs` writes result rows to
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
stage them. `stageAs` writes result rows to staged-dataset storage, which
|
|
49
|
+
has a per-user quota and an app-wide limit. Going over either removes the
|
|
50
|
+
least recently written datasets (the user's own for the per-user quota, any
|
|
51
|
+
user's for the app-wide limit), and a write too large to fit even then fails.
|
|
52
|
+
Do not clear existing staged datasets to make room. If a metadata request cannot be
|
|
51
53
|
read without staging, narrow the request or return only the required property
|
|
52
54
|
names, labels, and types through a read-only path.
|
|
53
55
|
- `provider-api-request` with `provider: "hubspot"` — arbitrary HubSpot HTTP
|
|
@@ -5,6 +5,10 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
5
5
|
|
|
6
6
|
## 2026-10-22
|
|
7
7
|
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- Blocks with several comment threads fold into one stack in the margin, which opens in place when you click it or a highlight
|
|
11
|
+
|
|
8
12
|
### Improved
|
|
9
13
|
|
|
10
14
|
- A collection linked to a big GitHub folder fills faster, and pushes to other linked collections aren't held up while it does
|
|
@@ -13,6 +17,7 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
13
17
|
|
|
14
18
|
### Fixed
|
|
15
19
|
|
|
20
|
+
- Opening a page no longer saves an edit again after another open tab's save already stored it.
|
|
16
21
|
- Changes made from a menu or popover, such as an image's alt text, are always saved.
|
|
17
22
|
- Agents can read saved page titles and text after an unrelated icon change fails.
|
|
18
23
|
- Text an agent writes inside a callout, column or synced block without indenting it now shows on the page and survives your edits.
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import type { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
import { IconChevronUp } from "@tabler/icons-react";
|
|
3
|
+
import { forwardRef, useEffect, useId, useRef, type ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
import type { CommentThread } from "@/hooks/use-comments";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
CommentAvatar,
|
|
10
|
+
CommentRow,
|
|
11
|
+
renderCommentBody,
|
|
12
|
+
useCommentTimestamp,
|
|
13
|
+
} from "./CommentRow";
|
|
14
|
+
|
|
15
|
+
type Translate = ReturnType<typeof useT>;
|
|
16
|
+
|
|
17
|
+
/** Two cards' edges under a stack, so it reads as more than one thread. */
|
|
18
|
+
export function CommentStackSheets() {
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<span
|
|
22
|
+
aria-hidden
|
|
23
|
+
className="pointer-events-none absolute bottom-0 left-6 right-8 top-8 rounded-xl bg-popover shadow-comment-card ring-1 ring-border/60"
|
|
24
|
+
data-comment-stack-sheet
|
|
25
|
+
/>
|
|
26
|
+
<span
|
|
27
|
+
aria-hidden
|
|
28
|
+
className="pointer-events-none absolute bottom-1 left-4 right-6 top-4 rounded-xl bg-popover shadow-comment-card ring-1 ring-border/60"
|
|
29
|
+
data-comment-stack-sheet
|
|
30
|
+
/>
|
|
31
|
+
</>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The first authors of a stack's threads, without repeats: email, name. */
|
|
36
|
+
function stackAuthors(threads: readonly CommentThread[]) {
|
|
37
|
+
const authors = new Map<string, string>();
|
|
38
|
+
for (const thread of threads) {
|
|
39
|
+
const first = thread.comments[0];
|
|
40
|
+
if (!first || authors.has(first.author_email)) continue;
|
|
41
|
+
authors.set(first.author_email, first.author_name ?? first.author_email);
|
|
42
|
+
if (authors.size === 3) break;
|
|
43
|
+
}
|
|
44
|
+
return [...authors];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function StackAvatars({ threads }: { threads: readonly CommentThread[] }) {
|
|
48
|
+
return (
|
|
49
|
+
<span className="flex -space-x-1">
|
|
50
|
+
{stackAuthors(threads).map(([email, name]) => (
|
|
51
|
+
<CommentAvatar
|
|
52
|
+
key={email}
|
|
53
|
+
email={email}
|
|
54
|
+
name={name}
|
|
55
|
+
className="size-5 text-[9px] ring-2 ring-popover"
|
|
56
|
+
/>
|
|
57
|
+
))}
|
|
58
|
+
</span>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** "+N more" with the avatars of the threads it counts. */
|
|
63
|
+
export function CommentStackMore({
|
|
64
|
+
threads,
|
|
65
|
+
t,
|
|
66
|
+
}: {
|
|
67
|
+
threads: readonly CommentThread[];
|
|
68
|
+
t: Translate;
|
|
69
|
+
}) {
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
<StackAvatars threads={threads} />
|
|
73
|
+
<span className="font-medium">
|
|
74
|
+
{t("comments.stackMore", { count: threads.length })}
|
|
75
|
+
</span>
|
|
76
|
+
</>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const footerClass =
|
|
81
|
+
"flex h-9 w-full items-center gap-2 border-t border-border/60 px-4 text-xs text-muted-foreground";
|
|
82
|
+
|
|
83
|
+
/** A new comment's footer on a folded stack; it opens the stack. */
|
|
84
|
+
export const CommentStackShowAll = forwardRef<
|
|
85
|
+
HTMLButtonElement,
|
|
86
|
+
{
|
|
87
|
+
threads: readonly CommentThread[];
|
|
88
|
+
onOpen: () => void;
|
|
89
|
+
t: Translate;
|
|
90
|
+
}
|
|
91
|
+
>(function CommentStackShowAll({ threads, onOpen, t }, ref) {
|
|
92
|
+
return (
|
|
93
|
+
<button
|
|
94
|
+
ref={ref}
|
|
95
|
+
type="button"
|
|
96
|
+
className={cn(
|
|
97
|
+
footerClass,
|
|
98
|
+
"text-start hover:bg-accent/40 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
|
|
99
|
+
)}
|
|
100
|
+
aria-expanded={false}
|
|
101
|
+
aria-label={t("comments.stackShowAll", { count: threads.length })}
|
|
102
|
+
onClick={(event) => {
|
|
103
|
+
event.stopPropagation();
|
|
104
|
+
onOpen();
|
|
105
|
+
}}
|
|
106
|
+
data-comment-stack-show-all
|
|
107
|
+
>
|
|
108
|
+
<CommentStackMore threads={threads} t={t} />
|
|
109
|
+
</button>
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* A block's open threads folded into one card: the front thread's quote and
|
|
115
|
+
* first comment, with the others counted below.
|
|
116
|
+
*/
|
|
117
|
+
export function CommentStackCard({
|
|
118
|
+
stackKey,
|
|
119
|
+
heightId,
|
|
120
|
+
threads,
|
|
121
|
+
front,
|
|
122
|
+
isActive,
|
|
123
|
+
onOpen,
|
|
124
|
+
onHoverChange,
|
|
125
|
+
onHeightChange,
|
|
126
|
+
t,
|
|
127
|
+
}: {
|
|
128
|
+
stackKey: string;
|
|
129
|
+
/** The id the margin lays this card out under. */
|
|
130
|
+
heightId: string;
|
|
131
|
+
threads: readonly CommentThread[];
|
|
132
|
+
front: CommentThread;
|
|
133
|
+
isActive: boolean;
|
|
134
|
+
onOpen: () => void;
|
|
135
|
+
onHoverChange: (hovered: boolean) => void;
|
|
136
|
+
onHeightChange: (threadId: string, height: number) => void;
|
|
137
|
+
t: Translate;
|
|
138
|
+
}) {
|
|
139
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
140
|
+
const descriptionId = useId();
|
|
141
|
+
const timestamp = useCommentTimestamp();
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
const element = ref.current;
|
|
144
|
+
if (!element) return;
|
|
145
|
+
const update = () =>
|
|
146
|
+
onHeightChange(heightId, element.getBoundingClientRect().height);
|
|
147
|
+
update();
|
|
148
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
149
|
+
const observer = new ResizeObserver(update);
|
|
150
|
+
observer.observe(element);
|
|
151
|
+
return () => observer.disconnect();
|
|
152
|
+
}, [heightId, onHeightChange]);
|
|
153
|
+
const first = front.comments[0];
|
|
154
|
+
const firstName = first
|
|
155
|
+
? (first.author_name ?? first.author_email.split("@")[0])
|
|
156
|
+
: null;
|
|
157
|
+
const replies = front.comments.length - 1;
|
|
158
|
+
const others = threads.filter((thread) => thread !== front);
|
|
159
|
+
return (
|
|
160
|
+
<div
|
|
161
|
+
ref={ref}
|
|
162
|
+
className="group/stack relative pb-2"
|
|
163
|
+
data-comment-stack={stackKey}
|
|
164
|
+
data-comment-stack-state="folded"
|
|
165
|
+
data-comment-stack-front={front.threadId}
|
|
166
|
+
onMouseEnter={() => onHoverChange(true)}
|
|
167
|
+
onMouseLeave={() => onHoverChange(false)}
|
|
168
|
+
>
|
|
169
|
+
<CommentStackSheets />
|
|
170
|
+
<div
|
|
171
|
+
className={cn(
|
|
172
|
+
"relative mx-2 mr-4 overflow-hidden rounded-xl bg-popover ring-1 ring-border/60 shadow-comment-card transition-[box-shadow,translate] duration-[260ms] ease-[var(--ease-drawer)] motion-reduce:transform-none motion-reduce:transition-none",
|
|
173
|
+
isActive
|
|
174
|
+
? "-translate-x-2 shadow-comment-emphasis ring-foreground/15"
|
|
175
|
+
: "group-hover/stack:-translate-x-2 group-hover/stack:shadow-comment-emphasis group-focus-within/stack:-translate-x-2 group-focus-within/stack:shadow-comment-emphasis motion-reduce:group-hover/stack:translate-x-0 motion-reduce:group-focus-within/stack:translate-x-0",
|
|
176
|
+
)}
|
|
177
|
+
>
|
|
178
|
+
{/* Inert keeps the preview's links out of reach, and leaves it out of
|
|
179
|
+
the open button's description too; the hidden copy below is
|
|
180
|
+
what a screen reader hears. */}
|
|
181
|
+
<div inert className="grid grid-cols-1 gap-3.5 px-4 pb-3.5 pt-3.5">
|
|
182
|
+
{front.quotedText ? (
|
|
183
|
+
<p className="-mb-1 line-clamp-1 border-s-2 border-border ps-2.5 text-sm text-muted-foreground">
|
|
184
|
+
{front.quotedText}
|
|
185
|
+
</p>
|
|
186
|
+
) : null}
|
|
187
|
+
{first ? (
|
|
188
|
+
<CommentRow
|
|
189
|
+
avatar={
|
|
190
|
+
<CommentAvatar
|
|
191
|
+
email={first.author_email}
|
|
192
|
+
name={first.author_name ?? first.author_email}
|
|
193
|
+
/>
|
|
194
|
+
}
|
|
195
|
+
name={firstName}
|
|
196
|
+
timestamp={{
|
|
197
|
+
...timestamp(first.created_at),
|
|
198
|
+
dateTime: first.created_at,
|
|
199
|
+
}}
|
|
200
|
+
>
|
|
201
|
+
<span className="line-clamp-3">
|
|
202
|
+
{renderCommentBody(first.content, first.mentions)}
|
|
203
|
+
</span>
|
|
204
|
+
</CommentRow>
|
|
205
|
+
) : null}
|
|
206
|
+
{replies > 0 ? (
|
|
207
|
+
<p className="-mt-2 ps-9.5 text-xs text-muted-foreground">
|
|
208
|
+
{t("comments.replyCount", { count: replies })}
|
|
209
|
+
</p>
|
|
210
|
+
) : null}
|
|
211
|
+
</div>
|
|
212
|
+
<div inert className={footerClass} data-comment-stack-footer>
|
|
213
|
+
<CommentStackMore threads={others} t={t} />
|
|
214
|
+
</div>
|
|
215
|
+
<div hidden id={descriptionId} data-comment-stack-description>
|
|
216
|
+
{front.quotedText ? <p>{front.quotedText}</p> : null}
|
|
217
|
+
{first ? (
|
|
218
|
+
<>
|
|
219
|
+
<p>{firstName}</p>
|
|
220
|
+
<p>{renderCommentBody(first.content, first.mentions)}</p>
|
|
221
|
+
</>
|
|
222
|
+
) : null}
|
|
223
|
+
{replies > 0 ? (
|
|
224
|
+
<p>{t("comments.replyCount", { count: replies })}</p>
|
|
225
|
+
) : null}
|
|
226
|
+
{stackAuthors(others).map(([email, name]) => (
|
|
227
|
+
<p key={email}>{name}</p>
|
|
228
|
+
))}
|
|
229
|
+
<p>{t("comments.stackMore", { count: others.length })}</p>
|
|
230
|
+
</div>
|
|
231
|
+
<button
|
|
232
|
+
type="button"
|
|
233
|
+
className="absolute inset-0 rounded-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
234
|
+
aria-expanded={false}
|
|
235
|
+
aria-label={t("comments.stackShowAll", { count: threads.length })}
|
|
236
|
+
aria-describedby={descriptionId}
|
|
237
|
+
onClick={(event) => {
|
|
238
|
+
event.stopPropagation();
|
|
239
|
+
onOpen();
|
|
240
|
+
}}
|
|
241
|
+
data-comment-stack-open
|
|
242
|
+
/>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Above an open stack's cards: folds them back into one. */
|
|
249
|
+
export function CommentStackHeader({
|
|
250
|
+
stackKey,
|
|
251
|
+
top,
|
|
252
|
+
onCollapse,
|
|
253
|
+
t,
|
|
254
|
+
}: {
|
|
255
|
+
stackKey: string;
|
|
256
|
+
top: number;
|
|
257
|
+
onCollapse: () => void;
|
|
258
|
+
t: Translate;
|
|
259
|
+
}) {
|
|
260
|
+
return (
|
|
261
|
+
<div
|
|
262
|
+
className="absolute inset-x-2 flex h-7 items-center transition-[top] duration-[260ms] ease-[var(--ease-drawer)] motion-reduce:transition-none"
|
|
263
|
+
style={{ top }}
|
|
264
|
+
data-comment-stack={stackKey}
|
|
265
|
+
data-comment-stack-state="open"
|
|
266
|
+
>
|
|
267
|
+
<button
|
|
268
|
+
type="button"
|
|
269
|
+
className="-ms-1.5 inline-flex h-7 items-center gap-1 rounded-md px-1.5 text-xs font-medium text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
270
|
+
aria-expanded
|
|
271
|
+
onClick={(event) => {
|
|
272
|
+
event.stopPropagation();
|
|
273
|
+
onCollapse();
|
|
274
|
+
}}
|
|
275
|
+
data-comment-stack-collapse
|
|
276
|
+
>
|
|
277
|
+
<IconChevronUp className="size-3.5" aria-hidden />
|
|
278
|
+
{t("comments.stackCollapse")}
|
|
279
|
+
</button>
|
|
280
|
+
</div>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** The line beside an open stack's cards that ties them to one block. */
|
|
285
|
+
export function CommentStackGuide({
|
|
286
|
+
top,
|
|
287
|
+
height,
|
|
288
|
+
}: {
|
|
289
|
+
top: number;
|
|
290
|
+
height: number;
|
|
291
|
+
}): ReactNode {
|
|
292
|
+
if (height <= 0) return null;
|
|
293
|
+
return (
|
|
294
|
+
<span
|
|
295
|
+
aria-hidden
|
|
296
|
+
className="absolute start-0.5 w-0.5 rounded-full bg-border transition-[top,height] duration-[260ms] ease-[var(--ease-drawer)] motion-reduce:transition-none"
|
|
297
|
+
style={{ top, height }}
|
|
298
|
+
data-comment-stack-guide
|
|
299
|
+
/>
|
|
300
|
+
);
|
|
301
|
+
}
|