@agent-native/core-corpus 0.201.0-nightly-20261005183955 → 0.201.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/CHANGELOG.md +6 -0
- package/corpus/templates/assets/CHANGELOG.md +7 -0
- package/corpus/templates/brain/CHANGELOG.md +6 -0
- package/corpus/templates/calendar/CHANGELOG.md +7 -0
- package/corpus/templates/clips/CHANGELOG.md +24 -0
- package/corpus/templates/content/CHANGELOG.md +41 -0
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +21 -6
- package/corpus/templates/content/app/components/editor/TableHoverControls.tsx +139 -70
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +2 -0
- package/corpus/templates/content/app/components/editor/table-view.ts +73 -0
- package/corpus/templates/content/app/global.css +16 -8
- package/corpus/templates/content/changelog/2026-10-02-pages-stay-inside-the-window-at-every-width-long-inline-code.md +6 -0
- package/corpus/templates/content/e2e/playwright.config.ts +1 -1
- package/corpus/templates/design/CHANGELOG.md +41 -0
- package/corpus/templates/design/app/pages/Index.tsx +1 -1
- package/corpus/templates/design/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-designs.md +6 -0
- package/corpus/templates/mail/CHANGELOG.md +6 -0
- package/corpus/templates/plan/CHANGELOG.md +1 -0
- package/corpus/templates/slides/CHANGELOG.md +23 -0
- package/corpus/templates/slides/app/pages/Index.tsx +51 -24
- package/corpus/templates/slides/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-decks-a.md +6 -0
- package/package.json +1 -1
package/corpus/README.md
CHANGED
|
@@ -7,8 +7,14 @@ time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
|
7
7
|
|
|
8
8
|
### Improved
|
|
9
9
|
|
|
10
|
+
- Builder.io setup now explains free credits and the existing-account option.
|
|
11
|
+
- Owners and admins can save data source credentials for the whole organization or just for themselves.
|
|
10
12
|
- Retention reports now compare returns from paid and untagged signups.
|
|
11
13
|
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Events with a very long name, app, or page path no longer cause the rest of their batch to be lost
|
|
17
|
+
|
|
12
18
|
## 2026-10-01
|
|
13
19
|
|
|
14
20
|
### Improved
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable user-facing changes to Assets are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-02
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Builder.io setup copy now clarifies account use and available credits.
|
|
11
|
+
- Owners and admins can save image generation keys for the whole organization, which is now the default.
|
|
12
|
+
|
|
6
13
|
## 2026-10-01
|
|
7
14
|
|
|
8
15
|
### Fixed
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Brain are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-05
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Messages from private Slack channels the Brain app is invited to are now searchable by everyone in the org once they pass sensitivity screening. Syncs no longer look up channel members, so a member without a visible email no longer stops a channel from syncing. Personal sources stay visible only to their owner and the people they are shared with.
|
|
11
|
+
|
|
6
12
|
## 2026-10-02
|
|
7
13
|
|
|
8
14
|
### Improved
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Calendar are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-02
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Builder.io setup copy now clarifies account activation and sign-in.
|
|
11
|
+
- Owners and admins can save Apollo, HubSpot, Gong, and Pylon keys for the whole organization or just for themselves.
|
|
12
|
+
|
|
6
13
|
## 2026-10-01
|
|
7
14
|
|
|
8
15
|
### Improved
|
|
@@ -3,10 +3,34 @@
|
|
|
3
3
|
All notable user-facing changes to Clips are documented here. Open it any time
|
|
4
4
|
from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-05
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Confirming Discard recording now returns you to your library.
|
|
11
|
+
- Discarding a recording now removes its failed upload card from your library.
|
|
12
|
+
- Discarding a recovered recording no longer warns that it's open in another tab.
|
|
13
|
+
- Search results identify recordings in Trash and open them with Trash navigation.
|
|
14
|
+
|
|
15
|
+
## 2026-10-03
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Invalid Lab choices can be repaired from Labs settings.
|
|
20
|
+
|
|
6
21
|
## 2026-10-02
|
|
7
22
|
|
|
23
|
+
### Improved
|
|
24
|
+
|
|
25
|
+
- Builder.io setup now offers one-click activation and clear existing-account sign-in.
|
|
26
|
+
|
|
8
27
|
### Fixed
|
|
9
28
|
|
|
29
|
+
- Cancelled Rewind Clip setup can be retried immediately
|
|
30
|
+
- Long uploads (an hour or more) now transcribe reliably instead of failing.
|
|
31
|
+
- Recording countdowns begin during setup, with explicit cue outcomes and startup timing
|
|
32
|
+
- Recording visibility defaults no longer switch to Public when saved settings cannot be read.
|
|
33
|
+
- Screen recording startup now cleans up canceled Rewind setup and keeps countdown timing reliable on older macOS.
|
|
10
34
|
- Recording reminders and other actionable notifications show their message above the buttons
|
|
11
35
|
- Temporary upload authorization failures remain retryable, while permanently rejected Builder credentials trigger storage setup errors.
|
|
12
36
|
|
|
@@ -3,10 +3,51 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Content are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new").
|
|
5
5
|
|
|
6
|
+
## 2026-10-05
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Collection pages keep selected rows visible through failed refreshes, and review space stays in place while comments refresh.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Collection view context now survives quick page changes when the saved summary fits.
|
|
15
|
+
- Exact saved-view links keep the collection retry available when rows fail to load
|
|
16
|
+
- Expanding a Files folder now shares one navigation read across open branches, and legacy owner shares retain their row controls.
|
|
17
|
+
- Files navigation retries temporary failures consistently
|
|
18
|
+
- Shared page owners keep edit and manage controls in Files, and newly opened folders populate faster.
|
|
19
|
+
- Tagging an AI in a comment works again instead of failing right away with "AI request failed".
|
|
20
|
+
- The home loading shell keeps the layout of your last opened page.
|
|
21
|
+
- Typing `>` and a space, or inserting a toggle or callout, no longer freezes and crashes the page on a Mac.
|
|
22
|
+
|
|
23
|
+
## 2026-10-03
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- A malformed Lab preference no longer blocks unrelated editor commands.
|
|
28
|
+
|
|
29
|
+
## 2026-10-02
|
|
30
|
+
|
|
31
|
+
### Improved
|
|
32
|
+
|
|
33
|
+
- After a refresh, the Files sidebar shows the open page's folders in one load instead of one level at a time
|
|
34
|
+
- Builder.io setup instructions now use consistent action language across editor workflows.
|
|
35
|
+
- Large collections open faster
|
|
36
|
+
- Pages with open comments and collections with sorted or filtered views no longer jump while they load
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- A page link you can't open now says so, with the account you're signed in as, instead of opening another page. People who can open a private share link no longer see "This document is private" first.
|
|
41
|
+
- Comment edits and deletions now refresh collaborators with the document open.
|
|
42
|
+
- Pages stay inside the window at every width: long inline code and links wrap, and wide tables scroll inside their own frame instead of crushing their columns
|
|
43
|
+
- Suggest edits works on pages written by agents, including pages with Markdown tables, instead of refusing to start or rejecting each edit; suggestions inside a table cell are still not supported
|
|
44
|
+
- While you suggest edits, tables and other blocks that suggestions don't support yet are read-only, and an agent that tries to suggest a change inside one gets a clear message instead of "Internal server error".
|
|
45
|
+
|
|
6
46
|
## 2026-10-01
|
|
7
47
|
|
|
8
48
|
### Improved
|
|
9
49
|
|
|
50
|
+
- Home opens the page you were last on sooner
|
|
10
51
|
- Pages and the sidebar load in place instead of jumping around
|
|
11
52
|
|
|
12
53
|
### Fixed
|
|
@@ -42,6 +42,9 @@ import {
|
|
|
42
42
|
import { VisualEditor } from "./VisualEditor";
|
|
43
43
|
|
|
44
44
|
const BLOCK_FIELD_DRAG_THRESHOLD = 6;
|
|
45
|
+
// The default `auto` track grows to its widest unbreakable line, which widens
|
|
46
|
+
// the whole page body past the window; the track must be allowed to shrink.
|
|
47
|
+
const BLOCK_FIELDS_GRID = "grid grid-cols-[minmax(0,1fr)]";
|
|
45
48
|
|
|
46
49
|
interface DocumentBlockFieldsProps {
|
|
47
50
|
documentId: string;
|
|
@@ -309,7 +312,10 @@ export function DocumentBlockFields({
|
|
|
309
312
|
// that state could bind the body before we know which storage target owns it.
|
|
310
313
|
if (query.isError) {
|
|
311
314
|
return (
|
|
312
|
-
<div
|
|
315
|
+
<div
|
|
316
|
+
className={cn(BLOCK_FIELDS_GRID, "gap-1")}
|
|
317
|
+
data-block-fields-state="error"
|
|
318
|
+
>
|
|
313
319
|
<QueryErrorState
|
|
314
320
|
compact
|
|
315
321
|
onRetry={() => globalThis.location.reload()}
|
|
@@ -325,7 +331,7 @@ export function DocumentBlockFields({
|
|
|
325
331
|
case "loading":
|
|
326
332
|
return (
|
|
327
333
|
<div
|
|
328
|
-
className="
|
|
334
|
+
className={cn(BLOCK_FIELDS_GRID, "gap-1")}
|
|
329
335
|
data-block-fields-state="loading"
|
|
330
336
|
aria-busy="true"
|
|
331
337
|
>
|
|
@@ -334,7 +340,10 @@ export function DocumentBlockFields({
|
|
|
334
340
|
);
|
|
335
341
|
case "empty":
|
|
336
342
|
return (
|
|
337
|
-
<div
|
|
343
|
+
<div
|
|
344
|
+
className={cn(BLOCK_FIELDS_GRID, "gap-1")}
|
|
345
|
+
data-block-fields-state="empty"
|
|
346
|
+
>
|
|
338
347
|
{canEdit ? (
|
|
339
348
|
<p className="px-1 py-2 text-sm text-muted-foreground">
|
|
340
349
|
{t("editor.noBlocksFields")}
|
|
@@ -345,7 +354,10 @@ export function DocumentBlockFields({
|
|
|
345
354
|
case "solo":
|
|
346
355
|
if (state.target === "block_field_store") {
|
|
347
356
|
return (
|
|
348
|
-
<div
|
|
357
|
+
<div
|
|
358
|
+
className={cn(BLOCK_FIELDS_GRID, "gap-1")}
|
|
359
|
+
data-block-fields-state="solo"
|
|
360
|
+
>
|
|
349
361
|
<AdditionalBlockEditor
|
|
350
362
|
key={`${documentId}:${state.field.definition.id}`}
|
|
351
363
|
documentId={documentId}
|
|
@@ -359,7 +371,10 @@ export function DocumentBlockFields({
|
|
|
359
371
|
);
|
|
360
372
|
}
|
|
361
373
|
return (
|
|
362
|
-
<div
|
|
374
|
+
<div
|
|
375
|
+
className={cn(BLOCK_FIELDS_GRID, "gap-1")}
|
|
376
|
+
data-block-fields-state="solo"
|
|
377
|
+
>
|
|
363
378
|
{primaryEditor}
|
|
364
379
|
</div>
|
|
365
380
|
);
|
|
@@ -546,7 +561,7 @@ function MultiBlockFields({
|
|
|
546
561
|
}
|
|
547
562
|
|
|
548
563
|
return (
|
|
549
|
-
<div className=
|
|
564
|
+
<div className={BLOCK_FIELDS_GRID}>
|
|
550
565
|
<BlockFieldDragPreview preview={dragPreview} />
|
|
551
566
|
{blockFields.map((property, index) => {
|
|
552
567
|
const primary = isPrimaryBlocksField(property.definition.options);
|
|
@@ -165,7 +165,7 @@ function getCellAtAddress(
|
|
|
165
165
|
return getCells(row)[address.columnIndex] ?? null;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
function getSelectionOverlayRect(rects: DOMRect[]) {
|
|
168
|
+
function getSelectionOverlayRect(table: HTMLElement, rects: DOMRect[]) {
|
|
169
169
|
if (rects.length === 0) return null;
|
|
170
170
|
|
|
171
171
|
const left = Math.min(...rects.map((rect) => rect.left));
|
|
@@ -173,12 +173,32 @@ function getSelectionOverlayRect(rects: DOMRect[]) {
|
|
|
173
173
|
const top = Math.min(...rects.map((rect) => rect.top));
|
|
174
174
|
const bottom = Math.max(...rects.map((rect) => rect.bottom));
|
|
175
175
|
|
|
176
|
+
return clampToScrollport(
|
|
177
|
+
{ height: bottom - top, left, top, width: right - left },
|
|
178
|
+
getTableScrollport(table),
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Tables scroll sideways inside `.tableWrapper`, but these controls render
|
|
183
|
+
// beside the editor, outside its clipping, so they clip themselves to it.
|
|
184
|
+
function getTableScrollport(table: HTMLElement) {
|
|
185
|
+
return (table.closest(".tableWrapper") ?? table).getBoundingClientRect();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function clampToScrollport(
|
|
189
|
+
rect: SelectionOverlayRect,
|
|
190
|
+
scrollport: DOMRect,
|
|
191
|
+
): SelectionOverlayRect {
|
|
192
|
+
const clamp = (x: number) =>
|
|
193
|
+
Math.min(Math.max(x, scrollport.left), scrollport.right);
|
|
194
|
+
const left = clamp(rect.left);
|
|
195
|
+
|
|
176
196
|
return {
|
|
177
|
-
height:
|
|
197
|
+
height: rect.height,
|
|
178
198
|
left,
|
|
179
|
-
top,
|
|
180
|
-
width:
|
|
181
|
-
}
|
|
199
|
+
top: rect.top,
|
|
200
|
+
width: clamp(rect.left + rect.width) - left,
|
|
201
|
+
};
|
|
182
202
|
}
|
|
183
203
|
|
|
184
204
|
function getRowSelectionOverlayRect(
|
|
@@ -188,6 +208,7 @@ function getRowSelectionOverlayRect(
|
|
|
188
208
|
if (!address) return null;
|
|
189
209
|
|
|
190
210
|
return getSelectionOverlayRect(
|
|
211
|
+
table,
|
|
191
212
|
getCells(getRows(table)[address.rowIndex]).map((cell) =>
|
|
192
213
|
cell.getBoundingClientRect(),
|
|
193
214
|
),
|
|
@@ -201,6 +222,7 @@ function getColumnSelectionOverlayRect(
|
|
|
201
222
|
if (!address) return null;
|
|
202
223
|
|
|
203
224
|
return getSelectionOverlayRect(
|
|
225
|
+
table,
|
|
204
226
|
getRows(table)
|
|
205
227
|
.map((row) => getCells(row)[address.columnIndex])
|
|
206
228
|
.filter((cell): cell is HTMLElement => Boolean(cell))
|
|
@@ -381,6 +403,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
381
403
|
const [columnMenuOpen, setColumnMenuOpen] = useState(false);
|
|
382
404
|
const [rowMenuOpen, setRowMenuOpen] = useState(false);
|
|
383
405
|
const [viewRetry, setViewRetry] = useState(0);
|
|
406
|
+
const [, setGeometryRevision] = useState(0);
|
|
384
407
|
|
|
385
408
|
const holdTableUiSelection = () => {
|
|
386
409
|
tableUiPointerDownRef.current = true;
|
|
@@ -971,7 +994,19 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
971
994
|
syncOverlay();
|
|
972
995
|
};
|
|
973
996
|
|
|
974
|
-
const handleGeometryChange = () =>
|
|
997
|
+
const handleGeometryChange = () => {
|
|
998
|
+
syncOverlay();
|
|
999
|
+
setGeometryRevision((revision) => revision + 1);
|
|
1000
|
+
};
|
|
1001
|
+
// Page scrolls carry the overlay along with the tables, but a table
|
|
1002
|
+
// scrolled sideways inside its own `.tableWrapper` leaves the overlay behind.
|
|
1003
|
+
const handleScroll = (event: Event) => {
|
|
1004
|
+
if (event.target instanceof Node && view.dom.contains(event.target)) {
|
|
1005
|
+
handleGeometryChange();
|
|
1006
|
+
} else {
|
|
1007
|
+
syncOverlay();
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
975
1010
|
const observer = new MutationObserver(syncOverlay);
|
|
976
1011
|
|
|
977
1012
|
syncOverlay();
|
|
@@ -982,7 +1017,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
982
1017
|
document.addEventListener("click", handlePointerDown, true);
|
|
983
1018
|
document.addEventListener("pointermove", handleHoverPointerMove, true);
|
|
984
1019
|
window.addEventListener("resize", handleGeometryChange);
|
|
985
|
-
window.addEventListener("scroll",
|
|
1020
|
+
window.addEventListener("scroll", handleScroll, true);
|
|
986
1021
|
view.dom.addEventListener("keyup", handleKeyUp);
|
|
987
1022
|
|
|
988
1023
|
return () => {
|
|
@@ -992,7 +1027,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
992
1027
|
document.removeEventListener("click", handlePointerDown, true);
|
|
993
1028
|
document.removeEventListener("pointermove", handleHoverPointerMove, true);
|
|
994
1029
|
window.removeEventListener("resize", handleGeometryChange);
|
|
995
|
-
window.removeEventListener("scroll",
|
|
1030
|
+
window.removeEventListener("scroll", handleScroll, true);
|
|
996
1031
|
window.removeEventListener("pointermove", handlePointerMove);
|
|
997
1032
|
window.removeEventListener("pointerup", handlePointerUp);
|
|
998
1033
|
view.dom.removeEventListener("keyup", handleKeyUp);
|
|
@@ -1000,6 +1035,18 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1000
1035
|
};
|
|
1001
1036
|
}, [editor, viewRetry]);
|
|
1002
1037
|
|
|
1038
|
+
// Panels opening beside the page narrow the editor without a window resize.
|
|
1039
|
+
useEffect(() => {
|
|
1040
|
+
const view = getMountedEditorView(editor);
|
|
1041
|
+
if (!view || tables.length === 0) return;
|
|
1042
|
+
const observer = new ResizeObserver(() =>
|
|
1043
|
+
setGeometryRevision((revision) => revision + 1),
|
|
1044
|
+
);
|
|
1045
|
+
observer.observe(view.dom);
|
|
1046
|
+
for (const table of tables) observer.observe(table);
|
|
1047
|
+
return () => observer.disconnect();
|
|
1048
|
+
}, [editor, tables]);
|
|
1049
|
+
|
|
1003
1050
|
const view = getMountedEditorView(editor);
|
|
1004
1051
|
if (!view) return null;
|
|
1005
1052
|
|
|
@@ -1020,6 +1067,13 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1020
1067
|
: null);
|
|
1021
1068
|
const selectedTableRect =
|
|
1022
1069
|
selectedTable?.getBoundingClientRect() ?? selectedTableRectRef.current;
|
|
1070
|
+
const selectedScrollport = selectedTable
|
|
1071
|
+
? getTableScrollport(selectedTable)
|
|
1072
|
+
: null;
|
|
1073
|
+
const visibleSelectedRect =
|
|
1074
|
+
selectedRect && selectedScrollport
|
|
1075
|
+
? clampToScrollport(selectedRect, selectedScrollport)
|
|
1076
|
+
: null;
|
|
1023
1077
|
const selectedDimensions = selectedTable
|
|
1024
1078
|
? getTableDimensions(selectedTable)
|
|
1025
1079
|
: { rowCount: 0, columnCount: 0 };
|
|
@@ -1050,9 +1104,9 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1050
1104
|
typeof window === "undefined"
|
|
1051
1105
|
? Number.POSITIVE_INFINITY
|
|
1052
1106
|
: window.innerHeight;
|
|
1053
|
-
const columnMenuWouldOverflowRight =
|
|
1054
|
-
?
|
|
1055
|
-
|
|
1107
|
+
const columnMenuWouldOverflowRight = visibleSelectedRect
|
|
1108
|
+
? visibleSelectedRect.left +
|
|
1109
|
+
visibleSelectedRect.width / 2 +
|
|
1056
1110
|
COLUMN_OPTIONS_MENU_ALIGN_OFFSET +
|
|
1057
1111
|
COLUMN_OPTIONS_MENU_WIDTH >
|
|
1058
1112
|
viewportWidth - MENU_COLLISION_PADDING
|
|
@@ -1084,9 +1138,12 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1084
1138
|
|
|
1085
1139
|
return (
|
|
1086
1140
|
<>
|
|
1087
|
-
{
|
|
1141
|
+
{visibleSelectedRect &&
|
|
1142
|
+
selectedScrollport &&
|
|
1143
|
+
selectedTable &&
|
|
1144
|
+
selectedTableRect ? (
|
|
1088
1145
|
<>
|
|
1089
|
-
{selectedColumnOverlayRect ? (
|
|
1146
|
+
{selectedColumnOverlayRect?.width ? (
|
|
1090
1147
|
<div
|
|
1091
1148
|
className="pointer-events-none absolute z-20 rounded-[3px] border-2 border-primary/60 bg-primary/10"
|
|
1092
1149
|
data-testid="table-selected-column"
|
|
@@ -1099,7 +1156,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1099
1156
|
/>
|
|
1100
1157
|
) : null}
|
|
1101
1158
|
|
|
1102
|
-
{selectedRowOverlayRect ? (
|
|
1159
|
+
{selectedRowOverlayRect?.width ? (
|
|
1103
1160
|
<div
|
|
1104
1161
|
className="pointer-events-none absolute z-20 rounded-[3px] border-2 border-primary/60 bg-primary/10"
|
|
1105
1162
|
data-testid="table-selected-row"
|
|
@@ -1112,22 +1169,27 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1112
1169
|
/>
|
|
1113
1170
|
) : null}
|
|
1114
1171
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1172
|
+
{visibleSelectedRect.width ? (
|
|
1173
|
+
<div
|
|
1174
|
+
className="pointer-events-none absolute z-30 rounded-[3px] border-2 border-primary/75 bg-primary/10"
|
|
1175
|
+
data-testid="table-selected-cell"
|
|
1176
|
+
style={{
|
|
1177
|
+
left: visibleSelectedRect.left - wrapperRect.left,
|
|
1178
|
+
top: visibleSelectedRect.top - wrapperRect.top,
|
|
1179
|
+
width: visibleSelectedRect.width,
|
|
1180
|
+
height: visibleSelectedRect.height,
|
|
1181
|
+
}}
|
|
1182
|
+
/>
|
|
1183
|
+
) : null}
|
|
1125
1184
|
|
|
1126
1185
|
<DropdownMenu open={columnMenuOpen} onOpenChange={setColumnMenuOpen}>
|
|
1127
1186
|
<DropdownMenuTrigger asChild>
|
|
1128
1187
|
<button
|
|
1129
1188
|
aria-label={t("database.columnOptions")}
|
|
1130
|
-
className={
|
|
1189
|
+
className={cn(
|
|
1190
|
+
lineButtonClass,
|
|
1191
|
+
!visibleSelectedRect.width && "invisible",
|
|
1192
|
+
)}
|
|
1131
1193
|
data-testid="table-column-options"
|
|
1132
1194
|
onClickCapture={(event) => {
|
|
1133
1195
|
event.preventDefault();
|
|
@@ -1146,9 +1208,9 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1146
1208
|
}}
|
|
1147
1209
|
style={{
|
|
1148
1210
|
left:
|
|
1149
|
-
|
|
1211
|
+
visibleSelectedRect.left -
|
|
1150
1212
|
wrapperRect.left +
|
|
1151
|
-
|
|
1213
|
+
visibleSelectedRect.width / 2,
|
|
1152
1214
|
top:
|
|
1153
1215
|
selectedTableRect.top -
|
|
1154
1216
|
wrapperRect.top -
|
|
@@ -1290,13 +1352,13 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1290
1352
|
}}
|
|
1291
1353
|
style={{
|
|
1292
1354
|
left:
|
|
1293
|
-
selectedTableRect.left -
|
|
1355
|
+
Math.max(selectedTableRect.left, selectedScrollport.left) -
|
|
1294
1356
|
wrapperRect.left -
|
|
1295
1357
|
ROW_OPTIONS_HIT_WIDTH / 2,
|
|
1296
1358
|
top:
|
|
1297
|
-
|
|
1359
|
+
visibleSelectedRect.top -
|
|
1298
1360
|
wrapperRect.top +
|
|
1299
|
-
|
|
1361
|
+
visibleSelectedRect.height / 2,
|
|
1300
1362
|
height: ROW_OPTIONS_HIT_HEIGHT,
|
|
1301
1363
|
transform: "translateY(-50%)",
|
|
1302
1364
|
width: ROW_OPTIONS_HIT_WIDTH,
|
|
@@ -1416,55 +1478,62 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1416
1478
|
|
|
1417
1479
|
const tableId = getTableOverlayId(table);
|
|
1418
1480
|
const rect = table.getBoundingClientRect();
|
|
1419
|
-
const
|
|
1481
|
+
const scrollportRect = getTableScrollport(table);
|
|
1482
|
+
const visibleLeft = Math.max(rect.left, scrollportRect.left);
|
|
1483
|
+
const visibleRight = Math.min(rect.right, scrollportRect.right);
|
|
1484
|
+
const isTableEndVisible = rect.right <= visibleRight + 1;
|
|
1420
1485
|
const top = rect.top - wrapperRect.top;
|
|
1421
1486
|
const right = rect.right - wrapperRect.left;
|
|
1422
1487
|
const bottom = rect.bottom - wrapperRect.top;
|
|
1488
|
+
const visibleCenter =
|
|
1489
|
+
(visibleLeft + visibleRight) / 2 - wrapperRect.left;
|
|
1423
1490
|
const isColumnHandleVisible = hoveredEdges.columnTable === table;
|
|
1424
1491
|
const isRowHandleVisible = hoveredEdges.rowTable === table;
|
|
1425
1492
|
|
|
1426
1493
|
return (
|
|
1427
1494
|
<div key={tableId}>
|
|
1428
|
-
|
|
1429
|
-
<
|
|
1430
|
-
<
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
height: COLUMN_EDGE_HANDLE_HIT_HEIGHT,
|
|
1446
|
-
left: right - COLUMN_EDGE_HANDLE_HIT_WIDTH / 2,
|
|
1447
|
-
top: top + rect.height / 2,
|
|
1448
|
-
width: COLUMN_EDGE_HANDLE_HIT_WIDTH,
|
|
1449
|
-
}}
|
|
1450
|
-
type="button"
|
|
1451
|
-
>
|
|
1452
|
-
<span
|
|
1453
|
-
className={edgeHandleMarkerClass}
|
|
1495
|
+
{isTableEndVisible ? (
|
|
1496
|
+
<Tooltip delayDuration={EDGE_HANDLE_TOOLTIP_DELAY}>
|
|
1497
|
+
<TooltipTrigger asChild>
|
|
1498
|
+
<button
|
|
1499
|
+
aria-label={t("database.tableColumnHandle")}
|
|
1500
|
+
className={cn(
|
|
1501
|
+
handleClass,
|
|
1502
|
+
"cursor-col-resize -translate-y-1/2",
|
|
1503
|
+
isColumnHandleVisible && "opacity-100",
|
|
1504
|
+
)}
|
|
1505
|
+
data-table-edge-control
|
|
1506
|
+
data-table-edge="column"
|
|
1507
|
+
data-table-id={tableId}
|
|
1508
|
+
data-testid="table-column-handle"
|
|
1509
|
+
onPointerDown={(event) =>
|
|
1510
|
+
startHandlePointer("column", table, event)
|
|
1511
|
+
}
|
|
1454
1512
|
style={{
|
|
1455
|
-
height:
|
|
1456
|
-
|
|
1513
|
+
height: COLUMN_EDGE_HANDLE_HIT_HEIGHT,
|
|
1514
|
+
left: right - COLUMN_EDGE_HANDLE_HIT_WIDTH / 2,
|
|
1515
|
+
top: top + rect.height / 2,
|
|
1516
|
+
width: COLUMN_EDGE_HANDLE_HIT_WIDTH,
|
|
1457
1517
|
}}
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1518
|
+
type="button"
|
|
1519
|
+
>
|
|
1520
|
+
<span
|
|
1521
|
+
className={edgeHandleMarkerClass}
|
|
1522
|
+
style={{
|
|
1523
|
+
height: EDGE_HANDLE_LENGTH,
|
|
1524
|
+
width: EDGE_HANDLE_THICKNESS,
|
|
1525
|
+
}}
|
|
1526
|
+
/>
|
|
1527
|
+
</button>
|
|
1528
|
+
</TooltipTrigger>
|
|
1529
|
+
<TooltipContent>
|
|
1530
|
+
<strong>{t("database.click")}</strong>{" "}
|
|
1531
|
+
{t("database.toAddAColumn")}{" "}
|
|
1532
|
+
<strong>{t("database.drag")}</strong>{" "}
|
|
1533
|
+
{t("database.toAddOrRemoveColumns")}
|
|
1534
|
+
</TooltipContent>
|
|
1535
|
+
</Tooltip>
|
|
1536
|
+
) : null}
|
|
1468
1537
|
|
|
1469
1538
|
<Tooltip delayDuration={EDGE_HANDLE_TOOLTIP_DELAY}>
|
|
1470
1539
|
<TooltipTrigger asChild>
|
|
@@ -1484,7 +1553,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
|
|
|
1484
1553
|
}
|
|
1485
1554
|
style={{
|
|
1486
1555
|
height: ROW_EDGE_HANDLE_HIT_HEIGHT,
|
|
1487
|
-
left:
|
|
1556
|
+
left: visibleCenter,
|
|
1488
1557
|
top: bottom - ROW_EDGE_HANDLE_HIT_HEIGHT / 2,
|
|
1489
1558
|
width: ROW_EDGE_HANDLE_HIT_WIDTH,
|
|
1490
1559
|
}}
|
|
@@ -166,6 +166,7 @@ import {
|
|
|
166
166
|
type SuggestionPresentationTransition,
|
|
167
167
|
} from "./suggestions/presentation-rebase";
|
|
168
168
|
import { SuggestingReadOnlyBlocks } from "./suggestions/read-only-blocks";
|
|
169
|
+
import { ContentTableView } from "./table-view";
|
|
169
170
|
import { TableHoverControls } from "./TableHoverControls";
|
|
170
171
|
|
|
171
172
|
function compareDocumentBodyRevisions(
|
|
@@ -2645,6 +2646,7 @@ export function createVisualEditorExtensions({
|
|
|
2645
2646
|
MediaSourceCommit.configure({ onMediaSourceCommitted }),
|
|
2646
2647
|
CustomTable.configure({
|
|
2647
2648
|
resizable: true,
|
|
2649
|
+
View: ContentTableView,
|
|
2648
2650
|
HTMLAttributes: { class: "notion-table" },
|
|
2649
2651
|
}),
|
|
2650
2652
|
TableRow,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { TableView } from "@tiptap/extension-table";
|
|
2
|
+
import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
|
|
3
|
+
import type { EditorView } from "@tiptap/pm/view";
|
|
4
|
+
|
|
5
|
+
// The table's CSS keeps it at least as wide as the page, so this floor only
|
|
6
|
+
// matters once unresized columns stop fitting: the table then scrolls inside
|
|
7
|
+
// `.tableWrapper` instead of squeezing each column to a letter per line.
|
|
8
|
+
// Tiptap's `cellMinWidth` stays small because it is also the drag minimum.
|
|
9
|
+
export const READABLE_TABLE_COLUMN_MIN_WIDTH = 96;
|
|
10
|
+
|
|
11
|
+
// Column drags rewrite the table's inline `min-width` on every frame, so the
|
|
12
|
+
// floor lives in a custom property that the stylesheet enforces instead.
|
|
13
|
+
export const READABLE_TABLE_MIN_WIDTH_PROPERTY = "--content-table-min-width";
|
|
14
|
+
|
|
15
|
+
export function readableTableMinWidth(colgroup: HTMLElement): number | null {
|
|
16
|
+
let total = 0;
|
|
17
|
+
let hasUnsizedColumn = false;
|
|
18
|
+
for (const col of Array.from(colgroup.children)) {
|
|
19
|
+
const width = Number.parseFloat((col as HTMLElement).style.width);
|
|
20
|
+
if (width > 0) {
|
|
21
|
+
total += width;
|
|
22
|
+
} else {
|
|
23
|
+
total += READABLE_TABLE_COLUMN_MIN_WIDTH;
|
|
24
|
+
hasUnsizedColumn = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return hasUnsizedColumn ? total : null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class ContentTableView extends TableView {
|
|
31
|
+
// A column drag restyles the <col>s on every frame but writes the new width
|
|
32
|
+
// to the document only on release, so the floor follows the <col>s.
|
|
33
|
+
private readonly columnObserver = new MutationObserver(() =>
|
|
34
|
+
this.applyReadableMinWidth(),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
constructor(
|
|
38
|
+
node: ProseMirrorNode,
|
|
39
|
+
cellMinWidth: number,
|
|
40
|
+
view?: EditorView,
|
|
41
|
+
HTMLAttributes: Record<string, unknown> = {},
|
|
42
|
+
) {
|
|
43
|
+
super(node, cellMinWidth, view, HTMLAttributes);
|
|
44
|
+
this.applyReadableMinWidth();
|
|
45
|
+
this.columnObserver.observe(this.colgroup, {
|
|
46
|
+
attributeFilter: ["style"],
|
|
47
|
+
childList: true,
|
|
48
|
+
subtree: true,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override update(node: ProseMirrorNode) {
|
|
53
|
+
if (!super.update(node)) return false;
|
|
54
|
+
this.applyReadableMinWidth();
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
destroy() {
|
|
59
|
+
this.columnObserver.disconnect();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private applyReadableMinWidth() {
|
|
63
|
+
const minWidth = readableTableMinWidth(this.colgroup);
|
|
64
|
+
if (minWidth === null) {
|
|
65
|
+
this.table.style.removeProperty(READABLE_TABLE_MIN_WIDTH_PROPERTY);
|
|
66
|
+
} else {
|
|
67
|
+
this.table.style.setProperty(
|
|
68
|
+
READABLE_TABLE_MIN_WIDTH_PROPERTY,
|
|
69
|
+
`${minWidth}px`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -121,10 +121,14 @@
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
pre,
|
|
124
|
-
code {
|
|
124
|
+
pre code {
|
|
125
125
|
overflow-x: auto;
|
|
126
126
|
white-space: pre;
|
|
127
127
|
}
|
|
128
|
+
|
|
129
|
+
code {
|
|
130
|
+
white-space: pre-wrap;
|
|
131
|
+
}
|
|
128
132
|
}
|
|
129
133
|
|
|
130
134
|
.notion-logo-icon {
|
|
@@ -476,7 +480,7 @@
|
|
|
476
480
|
.notion-editor ul:not(.notion-task-list) > li,
|
|
477
481
|
.notion-editor ol > li {
|
|
478
482
|
display: grid;
|
|
479
|
-
grid-template-columns: minmax(1rem, auto) 1fr;
|
|
483
|
+
grid-template-columns: minmax(1rem, auto) minmax(0, 1fr);
|
|
480
484
|
column-gap: 0.5em;
|
|
481
485
|
}
|
|
482
486
|
|
|
@@ -567,7 +571,7 @@
|
|
|
567
571
|
}
|
|
568
572
|
.notion-editor .notion-task-list li {
|
|
569
573
|
display: grid;
|
|
570
|
-
grid-template-columns: 1rem 1fr;
|
|
574
|
+
grid-template-columns: 1rem minmax(0, 1fr);
|
|
571
575
|
column-gap: 0.5em;
|
|
572
576
|
}
|
|
573
577
|
.notion-editor .notion-task-list li label {
|
|
@@ -719,6 +723,7 @@
|
|
|
719
723
|
margin: 0.6em 0;
|
|
720
724
|
}
|
|
721
725
|
.notion-editor pre code {
|
|
726
|
+
white-space: pre;
|
|
722
727
|
font-family: inherit;
|
|
723
728
|
background: none;
|
|
724
729
|
padding: 0;
|
|
@@ -836,6 +841,7 @@
|
|
|
836
841
|
border-spacing: 0;
|
|
837
842
|
table-layout: fixed;
|
|
838
843
|
width: 100% !important;
|
|
844
|
+
min-width: var(--content-table-min-width, 0px) !important;
|
|
839
845
|
margin: 0;
|
|
840
846
|
overflow: hidden;
|
|
841
847
|
border-radius: var(--radius);
|
|
@@ -1063,7 +1069,7 @@
|
|
|
1063
1069
|
|
|
1064
1070
|
div[data-notion-callout] {
|
|
1065
1071
|
display: grid;
|
|
1066
|
-
grid-template-columns: auto 1fr;
|
|
1072
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
1067
1073
|
gap: 0.8rem;
|
|
1068
1074
|
align-items: start;
|
|
1069
1075
|
margin: 0.9em 0;
|
|
@@ -1430,7 +1436,7 @@ div[data-notion-column] > :last-child {
|
|
|
1430
1436
|
display: flex;
|
|
1431
1437
|
align-items: center;
|
|
1432
1438
|
width: min(100%, 42rem);
|
|
1433
|
-
min-width: min(18rem,
|
|
1439
|
+
min-width: min(18rem, 100%);
|
|
1434
1440
|
min-height: 10rem;
|
|
1435
1441
|
gap: 0.9rem;
|
|
1436
1442
|
border: 1px dashed hsl(var(--border));
|
|
@@ -1478,7 +1484,7 @@ video.media-block__content {
|
|
|
1478
1484
|
|
|
1479
1485
|
audio.media-block__content {
|
|
1480
1486
|
width: min(40rem, calc(100vw - 2rem));
|
|
1481
|
-
min-width: min(16.25rem,
|
|
1487
|
+
min-width: min(16.25rem, 100%);
|
|
1482
1488
|
min-height: 54px;
|
|
1483
1489
|
background: hsl(var(--muted));
|
|
1484
1490
|
}
|
|
@@ -1611,12 +1617,14 @@ audio.media-block__content {
|
|
|
1611
1617
|
outline: none;
|
|
1612
1618
|
}
|
|
1613
1619
|
|
|
1620
|
+
/* Even hidden, a handle box that reaches past the page's narrowest side
|
|
1621
|
+
padding (16px) lets a full-width image scroll the page sideways. */
|
|
1614
1622
|
.media-block__resize-handle--left {
|
|
1615
|
-
left: -
|
|
1623
|
+
left: -16px;
|
|
1616
1624
|
}
|
|
1617
1625
|
|
|
1618
1626
|
.media-block__resize-handle--right {
|
|
1619
|
-
right: -
|
|
1627
|
+
right: -16px;
|
|
1620
1628
|
}
|
|
1621
1629
|
|
|
1622
1630
|
.media-block__alt-badge {
|
|
@@ -3,7 +3,7 @@ import { defineConfig, devices } from "@playwright/test";
|
|
|
3
3
|
export default defineConfig({
|
|
4
4
|
testDir: ".",
|
|
5
5
|
testMatch:
|
|
6
|
-
/(registry-blocks|local-files|database-preview-menu|sidebar-delete|shared-personal-page|unreadable-page-link|realtime-collab)\.spec\.ts/,
|
|
6
|
+
/(registry-blocks|local-files|database-preview-menu|sidebar-delete|shared-personal-page|signup-landing|unreadable-page-link|content-responsive-layout|realtime-collab)\.spec\.ts/,
|
|
7
7
|
fullyParallel: true,
|
|
8
8
|
workers: process.env.CI ? 2 : 3,
|
|
9
9
|
retries: 2,
|
|
@@ -3,17 +3,58 @@
|
|
|
3
3
|
All notable user-facing changes to Design are documented here. Open it any time
|
|
4
4
|
from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-05
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- The Recent tab shows loading placeholders until your designs are ready.
|
|
11
|
+
|
|
12
|
+
## 2026-10-03
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Alt-drag can increase an oversized corner radius even when CSS did not normalize the radius map.
|
|
17
|
+
- Corner-radius handles resize oversized radii without jumping
|
|
18
|
+
- Cross-screen drops skip flex targets whose axis or item placement cannot be modeled.
|
|
19
|
+
- Layers dropped into visible canvas space beyond a Screen now stay on the board.
|
|
20
|
+
- Reopening a Visual Edit connection keeps screens in its saved project
|
|
21
|
+
- Visible Screen overflow no longer routes drops to the canvas
|
|
22
|
+
|
|
6
23
|
## 2026-10-02
|
|
7
24
|
|
|
25
|
+
### Improved
|
|
26
|
+
|
|
27
|
+
- Builder.io setup now routes account activation through the one-click flow.
|
|
28
|
+
|
|
8
29
|
### Fixed
|
|
9
30
|
|
|
31
|
+
- Cross-screen auto-layout drops avoid guessing when direction comes from stylesheet rules
|
|
32
|
+
- Cross-Screen grid drops preserve the selected cell and the layer's track span
|
|
33
|
+
- Design drops now keep the chosen grid cell and follow reverse flex order when falling back to a fitting container
|
|
34
|
+
- Editing a design source file now refreshes collaborators with that design open.
|
|
35
|
+
- Grid drops avoid cells occupied by generated content
|
|
36
|
+
- Grid drops avoid mis-targeting cells in scrolled grids
|
|
37
|
+
- Layers that exceed a frame's width or height now fall back to the nearest container that fits
|
|
38
|
+
- Oversized drops target the nearest container that can fit the dragged layer.
|
|
39
|
+
- Oversized layers can now drop into a fitting ancestor when a nested frame is too small
|
|
40
|
+
- Reverse auto-layout drops keep their visual and layer order aligned.
|
|
41
|
+
- Drag-and-drop placement follows item size, spacing, and visible order in reversed layouts.
|
|
10
42
|
- Cross-screen drag targets no longer jump when an earlier screen sends a late move.
|
|
11
43
|
- Cross-screen drags continue when focus moves between screens
|
|
12
44
|
|
|
13
45
|
## 2026-10-01
|
|
14
46
|
|
|
47
|
+
### Improved
|
|
48
|
+
|
|
49
|
+
- Collaborators on the same screen now appear in the avatar bar in overview.
|
|
50
|
+
- The Design home opens on Recent when designs are available, hides the empty Recent tab, and distinguishes designs you own from those shared with you.
|
|
51
|
+
|
|
15
52
|
### Fixed
|
|
16
53
|
|
|
54
|
+
- Edits from collaborators now show up in an open design without a refresh, including frame moves and added or deleted screens.
|
|
55
|
+
- PNG and PDF exports now preserve fonts, images, effects, and page framing in imported screens.
|
|
56
|
+
- Two people editing different parts of the same screen no longer lose edits, and one person's undo no longer reverts the other's changes.
|
|
57
|
+
- Viewers on a shared design now see an editor's changes within a few seconds instead of minutes.
|
|
17
58
|
- A prompt you send before connecting AI is sent automatically once you connect.
|
|
18
59
|
- Cross-Screen drags now apply modifier keys reliably when the source screen loses focus.
|
|
19
60
|
- Cross-screen drops now respect modifier keys at release.
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Mail are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-02
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Builder.io setup copy now clarifies the account action and available credits.
|
|
11
|
+
|
|
6
12
|
## 2026-10-01
|
|
7
13
|
|
|
8
14
|
### Improved
|
|
@@ -11,6 +11,7 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
11
11
|
|
|
12
12
|
### Fixed
|
|
13
13
|
|
|
14
|
+
- Two people editing one plan at the same time, or one of them offline, now keep both sets of edits, and opening a plan together no longer duplicates its content.
|
|
14
15
|
- Consecutive Plan edits now use the latest saved revision.
|
|
15
16
|
|
|
16
17
|
## 2026-09-25
|
|
@@ -3,10 +3,31 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Slides are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new").
|
|
5
5
|
|
|
6
|
+
## 2026-10-05
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- The Recent tab shows loading placeholders until your decks are ready.
|
|
11
|
+
|
|
12
|
+
## 2026-10-03
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Slide text edits preserve layout with inline-size containment.
|
|
17
|
+
|
|
6
18
|
## 2026-10-02
|
|
7
19
|
|
|
20
|
+
### Improved
|
|
21
|
+
|
|
22
|
+
- Builder.io setup now routes account activation through the one-click flow.
|
|
23
|
+
- Recent appears when you have accessible decks, and shared decks are shown when you have none of your own.
|
|
24
|
+
- In-place slide editing now supports slash commands, Markdown shortcuts, and reliable list authoring while preserving text styling.
|
|
25
|
+
- Slides refreshes faster when a collaborator changes the deck open in your tab.
|
|
26
|
+
|
|
8
27
|
### Fixed
|
|
9
28
|
|
|
29
|
+
- Markdown list shortcuts work when text inherits link formatting
|
|
30
|
+
- Only one queued message action menu stays open at a time
|
|
10
31
|
- Google Slides imports keep skipped slides and their images in the right place.
|
|
11
32
|
- Heading text stays intact when Backspace joins it into a styled block.
|
|
12
33
|
- Slide text editing now preserves formatting and caret placement across browsers.
|
|
@@ -15,11 +36,13 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
15
36
|
|
|
16
37
|
### Improved
|
|
17
38
|
|
|
39
|
+
- Filter decks by owner with an option to view items shared with me.
|
|
18
40
|
- Recover failed deck saves with explicit retry or reload
|
|
19
41
|
- The observability settings tab is now labeled Observability.
|
|
20
42
|
|
|
21
43
|
### Fixed
|
|
22
44
|
|
|
45
|
+
- Collaborators editing different text boxes on the same slide now keep both edits instead of hitting a text conflict, and comments, replies and resolves reach other open editors within about a second.
|
|
23
46
|
- A prompt you send before connecting AI is sent automatically once you connect, and a deck generation that ends without slides shows Try again instead of an empty canvas.
|
|
24
47
|
- Blank speaker notes can be edited and saved without a conflict.
|
|
25
48
|
- New deck prompts no longer add a default design system unless you choose one, and empty failed generations explain what happened.
|
|
@@ -2623,31 +2623,35 @@ export default function Index({ active = true }: { active?: boolean }) {
|
|
|
2623
2623
|
}
|
|
2624
2624
|
templates={<DeckTemplateLibrary enabled={isHome} />}
|
|
2625
2625
|
recent={
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
<div className="rounded-xl bg-card p-6 text-sm text-muted-foreground">
|
|
2643
|
-
{t("home.noDecksMatchSearch")}
|
|
2644
|
-
</div>
|
|
2645
|
-
) : (
|
|
2646
|
-
<div className="rounded-xl bg-card p-6 text-sm text-muted-foreground">
|
|
2647
|
-
{t("home.noDecksMatchFilter")}
|
|
2648
|
-
</div>
|
|
2626
|
+
viewState === "loading" ? (
|
|
2627
|
+
<DeckListLoadingSkeleton />
|
|
2628
|
+
) : viewState === "error" ? null : (
|
|
2629
|
+
<div className="agent-template-library-grid">
|
|
2630
|
+
{visibleDecks.map((deck) => (
|
|
2631
|
+
<DeckCard
|
|
2632
|
+
key={deck.id}
|
|
2633
|
+
deck={deck}
|
|
2634
|
+
onDelete={(id) => setDeckToDelete(id)}
|
|
2635
|
+
onRename={handleRename}
|
|
2636
|
+
onDuplicate={handleDuplicate}
|
|
2637
|
+
onToggleStar={handleToggleStar}
|
|
2638
|
+
isWorkspaceDefault={workspaceReferenceDeck?.id === deck.id}
|
|
2639
|
+
canSetWorkspaceDefault={canManageWorkspaceDefaults}
|
|
2640
|
+
onSetWorkspaceDefault={handleSetWorkspaceDefaultDeck}
|
|
2641
|
+
/>
|
|
2649
2642
|
))}
|
|
2650
|
-
|
|
2643
|
+
{visibleDecks.length === 0 &&
|
|
2644
|
+
(normalizedDeckSearch ? (
|
|
2645
|
+
<div className="rounded-xl bg-card p-6 text-sm text-muted-foreground">
|
|
2646
|
+
{t("home.noDecksMatchSearch")}
|
|
2647
|
+
</div>
|
|
2648
|
+
) : (
|
|
2649
|
+
<div className="rounded-xl bg-card p-6 text-sm text-muted-foreground">
|
|
2650
|
+
{t("home.noDecksMatchFilter")}
|
|
2651
|
+
</div>
|
|
2652
|
+
))}
|
|
2653
|
+
</div>
|
|
2654
|
+
)
|
|
2651
2655
|
}
|
|
2652
2656
|
/>
|
|
2653
2657
|
</ClientOnly>
|
|
@@ -2814,6 +2818,29 @@ export default function Index({ active = true }: { active?: boolean }) {
|
|
|
2814
2818
|
);
|
|
2815
2819
|
}
|
|
2816
2820
|
|
|
2821
|
+
function DeckListLoadingSkeleton() {
|
|
2822
|
+
return (
|
|
2823
|
+
<div className="agent-template-library-grid" aria-busy="true">
|
|
2824
|
+
{Array.from({ length: 8 }, (_, index) => (
|
|
2825
|
+
<div
|
|
2826
|
+
key={index}
|
|
2827
|
+
className="agent-template-library-card group relative min-w-0"
|
|
2828
|
+
aria-hidden="true"
|
|
2829
|
+
>
|
|
2830
|
+
<div className="agent-template-library-primary overflow-hidden rounded-xl border border-border bg-card">
|
|
2831
|
+
<div className="agent-template-library-preview bg-muted/30">
|
|
2832
|
+
<Skeleton className="size-full rounded-none" />
|
|
2833
|
+
</div>
|
|
2834
|
+
<div className="agent-template-library-caption">
|
|
2835
|
+
<Skeleton className="h-4 w-3/4" />
|
|
2836
|
+
</div>
|
|
2837
|
+
</div>
|
|
2838
|
+
</div>
|
|
2839
|
+
))}
|
|
2840
|
+
</div>
|
|
2841
|
+
);
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2817
2844
|
function DeckSearchInput({
|
|
2818
2845
|
value,
|
|
2819
2846
|
onChange,
|
package/package.json
CHANGED