@1agh/maude 0.45.1 → 0.46.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/apps/studio/acp/bridge.ts +628 -74
- package/apps/studio/acp/index.ts +172 -23
- package/apps/studio/acp/probe.ts +31 -7
- package/apps/studio/acp/transcript.ts +91 -5
- package/apps/studio/annotations-snap.ts +50 -10
- package/apps/studio/api.ts +344 -14
- package/apps/studio/artboard-guides-overlay.tsx +270 -0
- package/apps/studio/bin/_import-asset.mjs +35 -5
- package/apps/studio/bin/_pdf-playwright.mjs +35 -4
- package/apps/studio/bin/_png-playwright.mjs +38 -4
- package/apps/studio/bin/_pw-launch.mjs +52 -0
- package/apps/studio/bin/_pw-launch.test.mjs +90 -0
- package/apps/studio/bin/_smart-frames.mjs +419 -0
- package/apps/studio/bin/_smart-frames.test.mjs +140 -0
- package/apps/studio/bin/smart-frames.sh +30 -0
- package/apps/studio/canvas-edit.ts +302 -3
- package/apps/studio/canvas-lib.tsx +203 -11
- package/apps/studio/canvas-shell.tsx +167 -28
- package/apps/studio/client/app.jsx +678 -176
- package/apps/studio/client/panels/CapabilityBar.jsx +101 -0
- package/apps/studio/client/panels/ChatPanel.jsx +846 -133
- package/apps/studio/client/panels/ElicitationPrompt.jsx +429 -0
- package/apps/studio/client/panels/PermissionPrompt.jsx +119 -0
- package/apps/studio/client/panels/ReadinessList.jsx +17 -3
- package/apps/studio/client/panels/SettingsPanel.jsx +211 -0
- package/apps/studio/client/panels/ToolGroup.jsx +79 -0
- package/apps/studio/client/panels/acp-capabilities.js +82 -0
- package/apps/studio/client/panels/acp-elicitation.js +194 -0
- package/apps/studio/client/panels/acp-runtime.js +248 -9
- package/apps/studio/client/panels/acp-usage.js +65 -0
- package/apps/studio/client/panels/transcript-view.js +36 -0
- package/apps/studio/client/styles/6-acp-chat.css +689 -11
- package/apps/studio/dist/client.bundle.js +1738 -1736
- package/apps/studio/dist/comment-mount.js +2 -2
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/dom-selection.ts +20 -0
- package/apps/studio/export-dialog.tsx +138 -18
- package/apps/studio/exporters/pdf.ts +332 -18
- package/apps/studio/exporters/png.ts +45 -3
- package/apps/studio/footage/schema.ts +17 -1
- package/apps/studio/generation/gemma-models.ts +224 -0
- package/apps/studio/generation/prefs.ts +43 -0
- package/apps/studio/generation/whisper-models.test.ts +28 -1
- package/apps/studio/generation/whisper-models.ts +22 -7
- package/apps/studio/http.ts +246 -9
- package/apps/studio/print/marks.ts +113 -0
- package/apps/studio/print/units.ts +269 -0
- package/apps/studio/print-overlay-content.tsx +132 -0
- package/apps/studio/test/acp-bridge.test.ts +11 -6
- package/apps/studio/test/acp-capabilities.test.ts +123 -0
- package/apps/studio/test/acp-caps-bridge.test.ts +274 -0
- package/apps/studio/test/acp-elicitation-bridge.test.ts +475 -0
- package/apps/studio/test/acp-elicitation.test.ts +251 -0
- package/apps/studio/test/acp-mode-banner.test.ts +45 -0
- package/apps/studio/test/acp-permission-prompt.test.ts +77 -0
- package/apps/studio/test/acp-permission.test.ts +262 -0
- package/apps/studio/test/acp-session-allowed-tools.test.ts +91 -0
- package/apps/studio/test/acp-toolgroup.test.ts +76 -0
- package/apps/studio/test/acp-transcript-view.test.ts +71 -0
- package/apps/studio/test/acp-transcript.test.ts +75 -2
- package/apps/studio/test/acp-usage-bridge.test.ts +136 -0
- package/apps/studio/test/acp-usage.test.ts +143 -0
- package/apps/studio/test/annotations-snap.test.ts +56 -0
- package/apps/studio/test/artboard-guides-overlay.test.tsx +152 -0
- package/apps/studio/test/artboard-kinds.test.tsx +83 -0
- package/apps/studio/test/artboard-selection-attrs.test.ts +69 -0
- package/apps/studio/test/canvas-meta-api.test.ts +167 -0
- package/apps/studio/test/element-structural-edit.test.ts +250 -0
- package/apps/studio/test/exporters/png.test.ts +49 -1
- package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +158 -0
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +46 -0
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +42 -0
- package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +63 -0
- package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +51 -0
- package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +50 -0
- package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +56 -0
- package/apps/studio/test/import-asset.test.ts +31 -3
- package/apps/studio/test/pdf-print-boxes.test.ts +272 -0
- package/apps/studio/test/print-marks.test.ts +113 -0
- package/apps/studio/test/print-units.test.ts +173 -0
- package/apps/studio/test/use-snap-guides.test.ts +81 -0
- package/apps/studio/use-chrome-visibility.tsx +19 -0
- package/apps/studio/use-element-resize.tsx +21 -2
- package/apps/studio/use-snap-guides.tsx +73 -5
- package/apps/studio/use-spacing-handles.tsx +9 -5
- package/apps/studio/whats-new.json +62 -0
- package/cli/commands/design.mjs +116 -3
- package/cli/lib/pkg-root.mjs +42 -10
- package/cli/lib/pkg-root.test.mjs +33 -1
- package/package.json +11 -9
- package/plugins/design/dependencies.json +35 -0
|
@@ -101,7 +101,20 @@ import {
|
|
|
101
101
|
} from 'react';
|
|
102
102
|
|
|
103
103
|
import { ArtboardActivityOverlay } from './artboard-activity-overlay.tsx';
|
|
104
|
+
import {
|
|
105
|
+
ArtboardGuidesOverlay,
|
|
106
|
+
type GuideDefinitions,
|
|
107
|
+
type OverlayVisibility,
|
|
108
|
+
} from './artboard-guides-overlay.tsx';
|
|
104
109
|
import { CanvasShell } from './canvas-shell.tsx';
|
|
110
|
+
import type { ArtboardPrintProp } from './print/units.ts';
|
|
111
|
+
// feature-2-print-artboards T3 — side-effect import: registers the print
|
|
112
|
+
// kind's overlay content (bleed/trim/margin) into artboard-guides-overlay's
|
|
113
|
+
// registry at module load, per that file's own "call registerKindOverlay at
|
|
114
|
+
// module load" contract. Must live in the same module graph every canvas
|
|
115
|
+
// bundle already pulls in (canvas-lib IS that shared graph — DDR-025), so a
|
|
116
|
+
// canvas never renders without the registration having run first.
|
|
117
|
+
import './print-overlay-content.tsx';
|
|
105
118
|
import {
|
|
106
119
|
buildMoveArtboardsRecord,
|
|
107
120
|
diffLayoutPositions,
|
|
@@ -299,6 +312,21 @@ const ENGINE_CSS = `
|
|
|
299
312
|
color: var(--fg-1, #4a3f30);
|
|
300
313
|
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
301
314
|
}
|
|
315
|
+
/* T3 — per-kind chrome. Subtle tint on the header + a small glyph before the
|
|
316
|
+
label text, for any non-digital kind. digital (the default, and every
|
|
317
|
+
unmigrated canvas) renders no chip and no tint — byte-identical chrome. */
|
|
318
|
+
.dc-canvas .dc-artboard[data-dc-kind]:not([data-dc-kind='digital']) .dc-artboard-label {
|
|
319
|
+
background: color-mix(in oklab, var(--accent, var(--fg-2, #4a3f30)) 10%, var(--bg-2, #e8e3d8));
|
|
320
|
+
}
|
|
321
|
+
.dc-canvas .dc-artboard-kind-chip {
|
|
322
|
+
display: inline-flex;
|
|
323
|
+
align-items: center;
|
|
324
|
+
justify-content: center;
|
|
325
|
+
margin-right: 6px;
|
|
326
|
+
color: var(--accent, var(--fg-1, #4a3f30));
|
|
327
|
+
opacity: 0.85;
|
|
328
|
+
vertical-align: -1px;
|
|
329
|
+
}
|
|
302
330
|
.dc-canvas .dc-artboard-body {
|
|
303
331
|
flex: 1;
|
|
304
332
|
position: relative;
|
|
@@ -379,12 +407,25 @@ function ensureEngineStyles(): void {
|
|
|
379
407
|
// world-coord positioning) and by DCSection (which collapses inside the
|
|
380
408
|
// canvas) and by future T3 components (MiniMap, ZoomToolbar).
|
|
381
409
|
|
|
410
|
+
/**
|
|
411
|
+
* What an artboard IS — digital screen / print page / web flow / video comp.
|
|
412
|
+
* Absent JSX prop resolves to `digital` (DDR-027-consistent: JSX is truth,
|
|
413
|
+
* no meta PATCH lane). Drives chrome (T3), the guides overlay content
|
|
414
|
+
* registry (T4), and generation/editing rules downstream (feature-2-print,
|
|
415
|
+
* feature-3-web).
|
|
416
|
+
*/
|
|
417
|
+
export type ArtboardKind = 'digital' | 'print' | 'web' | 'video';
|
|
418
|
+
|
|
382
419
|
export interface ArtboardRect {
|
|
383
420
|
id: string;
|
|
384
421
|
x: number;
|
|
385
422
|
y: number;
|
|
386
423
|
w: number;
|
|
387
424
|
h: number;
|
|
425
|
+
/** Resolved kind (explicit `kind` prop, or `video` fallback via
|
|
426
|
+
* `subtreeHasVideoComp`, or `digital`) — JSX-authoritative, recomputed
|
|
427
|
+
* from `harvestArtboards` every render; never persisted to meta. */
|
|
428
|
+
kind: ArtboardKind;
|
|
388
429
|
}
|
|
389
430
|
|
|
390
431
|
export interface ViewportState {
|
|
@@ -445,8 +486,11 @@ interface ArtboardSeed {
|
|
|
445
486
|
id: string;
|
|
446
487
|
w: number;
|
|
447
488
|
h: number;
|
|
489
|
+
kind: ArtboardKind;
|
|
448
490
|
}
|
|
449
491
|
|
|
492
|
+
const ARTBOARD_KINDS: ReadonlySet<string> = new Set(['digital', 'print', 'web', 'video']);
|
|
493
|
+
|
|
450
494
|
/**
|
|
451
495
|
* Walk a children subtree harvesting DCArtboard descriptors in render order.
|
|
452
496
|
* DCSection (and any other wrapper) is traversed but doesn't appear in the
|
|
@@ -469,11 +513,22 @@ function harvestArtboards(children: ReactNode): ArtboardSeed[] {
|
|
|
469
513
|
(typeof type === 'function' &&
|
|
470
514
|
(type as { displayName?: string }).displayName === 'DCArtboard');
|
|
471
515
|
if (isArtboard) {
|
|
472
|
-
const props = node.props as {
|
|
516
|
+
const props = node.props as {
|
|
517
|
+
id?: string;
|
|
518
|
+
width?: number;
|
|
519
|
+
height?: number;
|
|
520
|
+
kind?: string;
|
|
521
|
+
children?: ReactNode;
|
|
522
|
+
};
|
|
523
|
+
const explicitKind =
|
|
524
|
+
typeof props.kind === 'string' && ARTBOARD_KINDS.has(props.kind)
|
|
525
|
+
? (props.kind as ArtboardKind)
|
|
526
|
+
: undefined;
|
|
473
527
|
out.push({
|
|
474
528
|
id: typeof props.id === 'string' && props.id.length > 0 ? props.id : `__ab_${auto}`,
|
|
475
529
|
w: typeof props.width === 'number' ? props.width : VP_GRID.w,
|
|
476
530
|
h: typeof props.height === 'number' ? props.height : VP_GRID.h,
|
|
531
|
+
kind: explicitKind ?? (subtreeHasVideoComp(props.children) ? 'video' : 'digital'),
|
|
477
532
|
});
|
|
478
533
|
auto++;
|
|
479
534
|
return;
|
|
@@ -529,6 +584,7 @@ function synthDefaultGrid(seeds: ArtboardSeed[]): ArtboardRect[] {
|
|
|
529
584
|
y: row * (cellH + VP_GRID.gutter),
|
|
530
585
|
w: seed.w,
|
|
531
586
|
h: seed.h,
|
|
587
|
+
kind: seed.kind,
|
|
532
588
|
};
|
|
533
589
|
});
|
|
534
590
|
}
|
|
@@ -565,6 +621,9 @@ function readCanvasMeta():
|
|
|
565
621
|
| {
|
|
566
622
|
layout?: { artboards?: ArtboardRect[] };
|
|
567
623
|
viewport?: ViewportState;
|
|
624
|
+
/** T6 — per-user overlay-visibility bag, GET-merged in from view.json
|
|
625
|
+
* server-side (never present in the versioned `.meta.json` itself). */
|
|
626
|
+
overlays?: OverlayVisibility;
|
|
568
627
|
}
|
|
569
628
|
| undefined {
|
|
570
629
|
if (typeof window === 'undefined') return undefined;
|
|
@@ -572,6 +631,7 @@ function readCanvasMeta():
|
|
|
572
631
|
__canvas_meta__?: {
|
|
573
632
|
layout?: { artboards?: ArtboardRect[] };
|
|
574
633
|
viewport?: ViewportState;
|
|
634
|
+
overlays?: OverlayVisibility;
|
|
575
635
|
};
|
|
576
636
|
};
|
|
577
637
|
return w.__canvas_meta__;
|
|
@@ -1487,6 +1547,21 @@ function DesignCanvasInner({ children, controls }: DesignCanvasProps) {
|
|
|
1487
1547
|
const hostRef = useRef<HTMLDivElement | null>(null);
|
|
1488
1548
|
const worldRef = useRef<HTMLDivElement | null>(null);
|
|
1489
1549
|
|
|
1550
|
+
// T6 — self-seed the (per-canvas, persisted) guides visibility into the
|
|
1551
|
+
// shared ChromeVisibilityContext once at mount, from the SAME
|
|
1552
|
+
// window.__canvas_meta__ snapshot the viewport/layout reads above use.
|
|
1553
|
+
// Unlike minimap/zoom/present (global shell prefs pushed in via postMessage
|
|
1554
|
+
// shortly after load), `guides` has no global default to race — it's
|
|
1555
|
+
// read directly out of this canvas's own meta, so there's nothing to wait
|
|
1556
|
+
// for. The shell's View-menu toggle then live-updates it through the same
|
|
1557
|
+
// `dgn:'view-chrome'` channel as the other three flags.
|
|
1558
|
+
// T6 — the per-canvas overlay-visibility self-seed used to live here, but
|
|
1559
|
+
// this component renders CanvasShell as its CHILD and the
|
|
1560
|
+
// ChromeVisibilityProvider mounts INSIDE CanvasShell — so this component's
|
|
1561
|
+
// own useChromeVisibility() was always null and the seed silently never
|
|
1562
|
+
// ran (dead code since the foundation feature). The working seed now lives
|
|
1563
|
+
// in canvas-shell.tsx's CanvasRouter, which sits inside the provider.
|
|
1564
|
+
|
|
1490
1565
|
const seeds = useMemo(() => harvestArtboards(children), [children]);
|
|
1491
1566
|
|
|
1492
1567
|
// Merge JSX-derived defaults with meta-persisted positions. Per DDR-027,
|
|
@@ -1511,6 +1586,10 @@ function DesignCanvasInner({ children, controls }: DesignCanvasProps) {
|
|
|
1511
1586
|
y: Number.isFinite(m.y) ? m.y : d.y,
|
|
1512
1587
|
w: typeof m.w === 'number' && m.w > 0 ? m.w : d.w,
|
|
1513
1588
|
h: typeof m.h === 'number' && m.h > 0 ? m.h : d.h,
|
|
1589
|
+
// kind is JSX-authoritative like w/h (DDR-027) but, unlike w/h, was
|
|
1590
|
+
// never part of the legacy persisted layout shape — always the fresh
|
|
1591
|
+
// seed value, no meta fallback to tolerate.
|
|
1592
|
+
kind: d.kind,
|
|
1514
1593
|
};
|
|
1515
1594
|
});
|
|
1516
1595
|
}, [seeds]);
|
|
@@ -1803,6 +1882,57 @@ export function DCSection({
|
|
|
1803
1882
|
}
|
|
1804
1883
|
DCSection.displayName = 'DCSection';
|
|
1805
1884
|
|
|
1885
|
+
/**
|
|
1886
|
+
* Small monochrome glyph shown in the SKU-strip header for a non-`digital`
|
|
1887
|
+
* artboard (T3). Mirrors the corner video-badge's stroke style (viewBox 16,
|
|
1888
|
+
* `currentColor`, ~1.2px stroke) for chrome consistency. `video` reuses that
|
|
1889
|
+
* exact badge glyph.
|
|
1890
|
+
*/
|
|
1891
|
+
function ArtboardKindIcon({ kind }: { kind: ArtboardKind }) {
|
|
1892
|
+
if (kind === 'print') {
|
|
1893
|
+
return (
|
|
1894
|
+
<svg viewBox="0 0 16 16" width="10" height="10" fill="none" aria-hidden="true">
|
|
1895
|
+
<rect
|
|
1896
|
+
x="3"
|
|
1897
|
+
y="1.5"
|
|
1898
|
+
width="10"
|
|
1899
|
+
height="5"
|
|
1900
|
+
rx="0.5"
|
|
1901
|
+
stroke="currentColor"
|
|
1902
|
+
strokeWidth="1.2"
|
|
1903
|
+
/>
|
|
1904
|
+
<rect x="1.5" y="6" width="13" height="6" rx="1" stroke="currentColor" strokeWidth="1.2" />
|
|
1905
|
+
<rect x="4.5" y="10.5" width="7" height="4" stroke="currentColor" strokeWidth="1.1" />
|
|
1906
|
+
</svg>
|
|
1907
|
+
);
|
|
1908
|
+
}
|
|
1909
|
+
if (kind === 'web') {
|
|
1910
|
+
return (
|
|
1911
|
+
<svg viewBox="0 0 16 16" width="10" height="10" fill="none" aria-hidden="true">
|
|
1912
|
+
<circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="1.2" />
|
|
1913
|
+
<path
|
|
1914
|
+
d="M2 8h12M8 2c2 2 2 10 0 12M8 2c-2 2-2 10 0 12"
|
|
1915
|
+
stroke="currentColor"
|
|
1916
|
+
strokeWidth="1.1"
|
|
1917
|
+
/>
|
|
1918
|
+
</svg>
|
|
1919
|
+
);
|
|
1920
|
+
}
|
|
1921
|
+
// video — same glyph as the corner Timeline badge.
|
|
1922
|
+
return (
|
|
1923
|
+
<svg viewBox="0 0 16 16" width="10" height="10" fill="none" aria-hidden="true">
|
|
1924
|
+
<rect x="1.5" y="4.5" width="8" height="7" rx="1.2" stroke="currentColor" strokeWidth="1.3" />
|
|
1925
|
+
<path
|
|
1926
|
+
d="M9.5 7l4-2.3v6.6l-4-2.3"
|
|
1927
|
+
stroke="currentColor"
|
|
1928
|
+
strokeWidth="1.3"
|
|
1929
|
+
strokeLinejoin="round"
|
|
1930
|
+
/>
|
|
1931
|
+
</svg>
|
|
1932
|
+
);
|
|
1933
|
+
}
|
|
1934
|
+
ArtboardKindIcon.displayName = 'ArtboardKindIcon';
|
|
1935
|
+
|
|
1806
1936
|
/**
|
|
1807
1937
|
* Bordered artboard with a SKU-strip header. Inside DesignCanvas its world
|
|
1808
1938
|
* position comes from meta.layout (or the synthesized default grid); the
|
|
@@ -1820,6 +1950,9 @@ export function DCArtboard({
|
|
|
1820
1950
|
padding,
|
|
1821
1951
|
layout,
|
|
1822
1952
|
gap,
|
|
1953
|
+
kind,
|
|
1954
|
+
guides,
|
|
1955
|
+
print,
|
|
1823
1956
|
children,
|
|
1824
1957
|
}: {
|
|
1825
1958
|
id: string;
|
|
@@ -1833,17 +1966,33 @@ export function DCArtboard({
|
|
|
1833
1966
|
fixed?: boolean;
|
|
1834
1967
|
/** `.dc-artboard-body` background (CSS color/token, e.g. "var(--bg-1)"). */
|
|
1835
1968
|
background?: string;
|
|
1836
|
-
/** `.dc-artboard-body` padding
|
|
1837
|
-
|
|
1969
|
+
/** `.dc-artboard-body` padding — px number, or a `var(--token)` string
|
|
1970
|
+
* (space-token binding from the Inspector's artboard panel). */
|
|
1971
|
+
padding?: number | string;
|
|
1838
1972
|
/** `.dc-artboard-body` layout mode. Default = the engine's plain block flow. */
|
|
1839
1973
|
layout?: 'block' | 'flex-col' | 'flex-row' | 'grid';
|
|
1840
|
-
/** `.dc-artboard-body` gap
|
|
1841
|
-
|
|
1974
|
+
/** `.dc-artboard-body` gap — px number or `var(--token)` string; only
|
|
1975
|
+
* visible under flex-col/flex-row/grid. */
|
|
1976
|
+
gap?: number | string;
|
|
1977
|
+
/** What this artboard IS — digital screen / print page / web flow / video
|
|
1978
|
+
* comp. Absent ⇒ `digital` (or `video` when the subtree contains a
|
|
1979
|
+
* `<VideoComp>`, for unmigrated canvases — see `subtreeHasVideoComp`).
|
|
1980
|
+
* An explicit prop always supersedes that structural fallback. */
|
|
1981
|
+
kind?: ArtboardKind;
|
|
1982
|
+
/** Generic layout guides (T5) — Figma-vocabulary columns/rows/grid,
|
|
1983
|
+
* versioned design intent. Kind-agnostic: any artboard can carry these
|
|
1984
|
+
* regardless of `kind`. Visibility is per-user (T6), not this prop. */
|
|
1985
|
+
guides?: GuideDefinitions;
|
|
1986
|
+
/** feature-2-print-artboards T2 — paper/orientation/bleed/margins intent.
|
|
1987
|
+
* Only meaningful when `kind="print"`; the overlay (T3) reads it to draw
|
|
1988
|
+
* bleed/trim/margin guides against THIS artboard's own resolved px size. */
|
|
1989
|
+
print?: ArtboardPrintProp;
|
|
1842
1990
|
children: ReactNode;
|
|
1843
1991
|
}) {
|
|
1844
1992
|
const ctx = useWorldContext();
|
|
1845
1993
|
const _controller = useViewportControllerContext();
|
|
1846
1994
|
const toolMode = useToolModeOptional();
|
|
1995
|
+
const chrome = useChromeVisibility();
|
|
1847
1996
|
const selSet = useSelectionSetOptional();
|
|
1848
1997
|
const dragBus = useDragStateContext();
|
|
1849
1998
|
// Phase 13 / DDR-029 — live "agent works here" overlay. Inert (present=false)
|
|
@@ -1853,10 +2002,15 @@ export function DCArtboard({
|
|
|
1853
2002
|
// its presence color + show its funny name instead of the generic file label.
|
|
1854
2003
|
const agent = useAgentPresence();
|
|
1855
2004
|
const rect = ctx ? ctx.rectFor(id) : null;
|
|
2005
|
+
// T1/T2 — explicit `kind` wins; `subtreeHasVideoComp` is the fallback that
|
|
2006
|
+
// keeps existing unmigrated video canvases badged identically without
|
|
2007
|
+
// requiring a JSX edit (Design Decision 1).
|
|
2008
|
+
const hasVideoContent = useMemo(() => subtreeHasVideoComp(children), [children]);
|
|
2009
|
+
const resolvedKind: ArtboardKind = kind ?? (hasVideoContent ? 'video' : 'digital');
|
|
1856
2010
|
// DDR-148 — badge video artboards in the header; clicking the badge opens
|
|
1857
2011
|
// the timeline panel via the same postMessage the context-menu "Open
|
|
1858
2012
|
// Timeline" entry already sends (canvas-shell.tsx artboardHasVideo/handler).
|
|
1859
|
-
const hasVideo =
|
|
2013
|
+
const hasVideo = resolvedKind === 'video';
|
|
1860
2014
|
const openTimeline = useCallback(
|
|
1861
2015
|
(e: ReactMouseEvent<HTMLButtonElement>) => {
|
|
1862
2016
|
e.stopPropagation();
|
|
@@ -1921,8 +2075,9 @@ export function DCArtboard({
|
|
|
1921
2075
|
const bodyStyle = useMemo<CSSProperties>(() => {
|
|
1922
2076
|
const st: CSSProperties = {};
|
|
1923
2077
|
if (background) st.background = background;
|
|
1924
|
-
|
|
1925
|
-
if (typeof
|
|
2078
|
+
// number → px; string → a var(--token) binding (validated server-side).
|
|
2079
|
+
if (typeof padding === 'number' || typeof padding === 'string') st.padding = padding;
|
|
2080
|
+
if (typeof gap === 'number' || typeof gap === 'string') st.gap = gap;
|
|
1926
2081
|
if (layout === 'flex-col') {
|
|
1927
2082
|
st.display = 'flex';
|
|
1928
2083
|
st.flexDirection = 'column';
|
|
@@ -1943,9 +2098,20 @@ export function DCArtboard({
|
|
|
1943
2098
|
const readBackAttrs = {
|
|
1944
2099
|
'data-dc-fixed': fixed ? 'true' : undefined,
|
|
1945
2100
|
'data-dc-bg': background,
|
|
1946
|
-
'data-dc-padding':
|
|
2101
|
+
'data-dc-padding': padding != null ? String(padding) : undefined,
|
|
1947
2102
|
'data-dc-layout': layout,
|
|
1948
|
-
'data-dc-gap':
|
|
2103
|
+
'data-dc-gap': gap != null ? String(gap) : undefined,
|
|
2104
|
+
// Always present (unlike the optional-override props above) — this is a
|
|
2105
|
+
// resolved classification, not a "no override" style knob. Chrome, the
|
|
2106
|
+
// Inspector kind picker (T8), and canvas-shell's artboardHasVideo gate
|
|
2107
|
+
// (T2) all key off this attribute.
|
|
2108
|
+
'data-dc-kind': resolvedKind,
|
|
2109
|
+
// feature-2-print-artboards T2 — read-back for the Inspector's print
|
|
2110
|
+
// picker (paper/orientation/bleed pre-fill), same "stamp the resolved
|
|
2111
|
+
// prop as JSON, parse it back" shape `guides` would need if it grew an
|
|
2112
|
+
// Inspector editor. Small object (≤ ~150 bytes), so a plain JSON attr is
|
|
2113
|
+
// simpler than adding parallel data-dc-print-* scalar attrs per field.
|
|
2114
|
+
'data-dc-print': print ? JSON.stringify(print) : undefined,
|
|
1949
2115
|
};
|
|
1950
2116
|
|
|
1951
2117
|
if (!ctx || !rect) {
|
|
@@ -2037,7 +2203,22 @@ export function DCArtboard({
|
|
|
2037
2203
|
}}
|
|
2038
2204
|
{...handleProps}
|
|
2039
2205
|
>
|
|
2040
|
-
<button
|
|
2206
|
+
<button
|
|
2207
|
+
type="button"
|
|
2208
|
+
className="dc-artboard-label sku"
|
|
2209
|
+
// a11y-auditor (T3 review) — the kind chip is aria-hidden (decorative,
|
|
2210
|
+
// redundant with the Inspector's Kind picker), so a non-digital kind
|
|
2211
|
+
// must still reach the artboard's own accessible name or it's
|
|
2212
|
+
// invisible to AT users entirely.
|
|
2213
|
+
aria-label={
|
|
2214
|
+
resolvedKind !== 'digital' ? `Artboard ${label}, ${resolvedKind}` : `Artboard ${label}`
|
|
2215
|
+
}
|
|
2216
|
+
>
|
|
2217
|
+
{resolvedKind !== 'digital' ? (
|
|
2218
|
+
<span className="dc-artboard-kind-chip" aria-hidden="true">
|
|
2219
|
+
<ArtboardKindIcon kind={resolvedKind} />
|
|
2220
|
+
</span>
|
|
2221
|
+
) : null}
|
|
2041
2222
|
{label}
|
|
2042
2223
|
</button>
|
|
2043
2224
|
{hasVideo ? (
|
|
@@ -2079,6 +2260,17 @@ export function DCArtboard({
|
|
|
2079
2260
|
color={agent?.color}
|
|
2080
2261
|
/>
|
|
2081
2262
|
) : null}
|
|
2263
|
+
{/* T4 — world-coord sibling, same reasoning as ArtboardActivityOverlay
|
|
2264
|
+
above: must stay OUTSIDE `.dc-artboard`'s contain:paint/
|
|
2265
|
+
content-visibility subtree so guides are never culled/frozen with
|
|
2266
|
+
exported content (they're never exported at all). */}
|
|
2267
|
+
<ArtboardGuidesOverlay
|
|
2268
|
+
rect={{ x: liveX, y: liveY, w: rect.w, h: rect.h }}
|
|
2269
|
+
kind={resolvedKind}
|
|
2270
|
+
guides={guides}
|
|
2271
|
+
print={print}
|
|
2272
|
+
visibility={{ guides: chrome?.guides ?? false, print: chrome?.print ?? false }}
|
|
2273
|
+
/>
|
|
2082
2274
|
</>
|
|
2083
2275
|
);
|
|
2084
2276
|
}
|
|
@@ -570,10 +570,17 @@ function getLastLayersArtboardId(): string | null {
|
|
|
570
570
|
// DDR-148 — an artboard hosting a <VideoComp> stamps a `[data-comp-id]`
|
|
571
571
|
// element inside it (see video-comp.tsx). Gates the artboard-chrome context
|
|
572
572
|
// menu's "Open Timeline" entry to artboards that actually have a sequence.
|
|
573
|
+
// T2 (feature-1-artboard-kinds-foundation) — merged with the resolved `kind`:
|
|
574
|
+
// an explicit `kind="video"` (DCArtboard's `data-dc-kind` readback) also
|
|
575
|
+
// qualifies, even before any `<VideoComp>` content exists yet; the structural
|
|
576
|
+
// `[data-comp-id]` check stays as the fallback for unmigrated canvases.
|
|
573
577
|
function artboardHasVideo(artboardId: string | null | undefined): boolean {
|
|
574
578
|
if (typeof document === 'undefined' || !artboardId) return false;
|
|
575
579
|
try {
|
|
576
|
-
|
|
580
|
+
const root = document.querySelector(`[data-dc-screen="${CSS.escape(artboardId)}"]`);
|
|
581
|
+
if (!root) return false;
|
|
582
|
+
if (root.getAttribute('data-dc-kind') === 'video') return true;
|
|
583
|
+
return !!root.querySelector('[data-comp-id]');
|
|
577
584
|
} catch {
|
|
578
585
|
return false;
|
|
579
586
|
}
|
|
@@ -1421,6 +1428,56 @@ function buildRegistry(deps: {
|
|
|
1421
1428
|
],
|
|
1422
1429
|
};
|
|
1423
1430
|
|
|
1431
|
+
// feature-1-artboard-kinds-foundation, T8 — kind-switch submenu, same
|
|
1432
|
+
// shape as themeItem above (a parent-only MenuItem whose onSelect never
|
|
1433
|
+
// fires). The write is main-origin-only (DDR-054): post to the parent
|
|
1434
|
+
// shell (dgn:'set-artboard-kind-request'), which calls
|
|
1435
|
+
// api.setArtboardKindOp and records undo — mirrors delete-artboard-request.
|
|
1436
|
+
const postArtboardKindRequest = (artboardId: string, kind: string | null): void => {
|
|
1437
|
+
try {
|
|
1438
|
+
window.parent.postMessage({ dgn: 'set-artboard-kind-request', artboardId, kind }, '*');
|
|
1439
|
+
} catch {
|
|
1440
|
+
/* detached / cross-origin */
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
const kindItem: MenuItem = {
|
|
1444
|
+
id: 'kind',
|
|
1445
|
+
label: 'Artboard kind',
|
|
1446
|
+
onSelect: () => {
|
|
1447
|
+
/* parent of a submenu — never invoked directly */
|
|
1448
|
+
},
|
|
1449
|
+
submenu: [
|
|
1450
|
+
{
|
|
1451
|
+
id: 'kind-digital',
|
|
1452
|
+
label: 'Digital (default)',
|
|
1453
|
+
onSelect: (target) => {
|
|
1454
|
+
if (target.artboardId) postArtboardKindRequest(target.artboardId, null);
|
|
1455
|
+
},
|
|
1456
|
+
},
|
|
1457
|
+
{
|
|
1458
|
+
id: 'kind-print',
|
|
1459
|
+
label: 'Print',
|
|
1460
|
+
onSelect: (target) => {
|
|
1461
|
+
if (target.artboardId) postArtboardKindRequest(target.artboardId, 'print');
|
|
1462
|
+
},
|
|
1463
|
+
},
|
|
1464
|
+
{
|
|
1465
|
+
id: 'kind-web',
|
|
1466
|
+
label: 'Web',
|
|
1467
|
+
onSelect: (target) => {
|
|
1468
|
+
if (target.artboardId) postArtboardKindRequest(target.artboardId, 'web');
|
|
1469
|
+
},
|
|
1470
|
+
},
|
|
1471
|
+
{
|
|
1472
|
+
id: 'kind-video',
|
|
1473
|
+
label: 'Video',
|
|
1474
|
+
onSelect: (target) => {
|
|
1475
|
+
if (target.artboardId) postArtboardKindRequest(target.artboardId, 'video');
|
|
1476
|
+
},
|
|
1477
|
+
},
|
|
1478
|
+
],
|
|
1479
|
+
};
|
|
1480
|
+
|
|
1424
1481
|
return {
|
|
1425
1482
|
element: [
|
|
1426
1483
|
[
|
|
@@ -1771,7 +1828,7 @@ function buildRegistry(deps: {
|
|
|
1771
1828
|
onSelect: () => distributeArtboards('y'),
|
|
1772
1829
|
},
|
|
1773
1830
|
],
|
|
1774
|
-
[themeItem],
|
|
1831
|
+
[themeItem, kindItem],
|
|
1775
1832
|
[
|
|
1776
1833
|
{
|
|
1777
1834
|
id: 'delete-artboard',
|
|
@@ -1938,6 +1995,34 @@ function CanvasRouter({
|
|
|
1938
1995
|
// consumes.
|
|
1939
1996
|
const chromeCtx = useChromeVisibility();
|
|
1940
1997
|
|
|
1998
|
+
// Dogfood follow-up (print artboards) — self-seed the per-canvas persisted
|
|
1999
|
+
// overlay visibility (view.json `overlays.guides`/`overlays.print`, GET-
|
|
2000
|
+
// merged into `window.__canvas_meta__` by _shell.html before mount) into
|
|
2001
|
+
// the chrome store, once per mount. This seed originally lived in
|
|
2002
|
+
// DesignCanvasInner (canvas-lib.tsx) — but that component renders
|
|
2003
|
+
// CanvasShell as its CHILD, and ChromeVisibilityProvider mounts INSIDE
|
|
2004
|
+
// CanvasShell, so DesignCanvasInner's own useChromeVisibility() was always
|
|
2005
|
+
// null and the seed silently never ran (dead since the foundation feature;
|
|
2006
|
+
// the generic `guides` toggle had no UI yet, so nothing surfaced it —
|
|
2007
|
+
// "Show print guides" is its first real consumer). CanvasRouter sits
|
|
2008
|
+
// inside the provider (it's the view-chrome bridge), so the seed works
|
|
2009
|
+
// here. Absent keys stay HIDDEN (the T6 gotcha — an old view.json must
|
|
2010
|
+
// not suddenly paint guides nobody asked for).
|
|
2011
|
+
const overlaysSeededRef = useRef(false);
|
|
2012
|
+
useEffect(() => {
|
|
2013
|
+
if (overlaysSeededRef.current || !chromeCtx) return;
|
|
2014
|
+
overlaysSeededRef.current = true;
|
|
2015
|
+
const w = window as unknown as {
|
|
2016
|
+
__canvas_meta__?: { overlays?: Record<string, boolean> };
|
|
2017
|
+
};
|
|
2018
|
+
const overlays = w.__canvas_meta__?.overlays;
|
|
2019
|
+
if (!overlays) return;
|
|
2020
|
+
const patch: { guides?: boolean; print?: boolean } = {};
|
|
2021
|
+
if (overlays.guides === true) patch.guides = true;
|
|
2022
|
+
if (overlays.print === true) patch.print = true;
|
|
2023
|
+
if (Object.keys(patch).length > 0) chromeCtx.setChrome(patch);
|
|
2024
|
+
}, [chromeCtx]);
|
|
2025
|
+
|
|
1941
2026
|
// Task A2 (feature-element-editing-robustness) — host-scroll-0 invariant.
|
|
1942
2027
|
// `.dc-canvas` (overflow:hidden) and each `.dc-artboard-body` are the engine's
|
|
1943
2028
|
// clip layers; the camera lives entirely in the `.dc-world` transform, and
|
|
@@ -2037,29 +2122,39 @@ function CanvasRouter({
|
|
|
2037
2122
|
// request-layers re-walks + posts the tree for an artboard.
|
|
2038
2123
|
if (m.dgn === 'select-by-id') {
|
|
2039
2124
|
const mm = m as { id?: string; artboardId?: string | null; index?: number };
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2125
|
+
// Dogfood follow-up — a bare ARTBOARD selection (no data-cd-id, the
|
|
2126
|
+
// ArtboardKnobs panel's own case) has no `mm.id` to resolve by, so
|
|
2127
|
+
// the element branch below never ran for it: after a structural
|
|
2128
|
+
// artboard write (kind/print/style/hug/resize) the Inspector kept
|
|
2129
|
+
// showing the PRE-edit attrs snapshot (e.g. "Digital" right after
|
|
2130
|
+
// switching to "Print") until the user manually re-clicked the
|
|
2131
|
+
// artboard. Resolve by the SAME `[data-dc-screen="<id>"]` selector
|
|
2132
|
+
// ArtboardKnobs itself reads its selection from (dom-selection.ts
|
|
2133
|
+
// `hoverTargetToSelection` "2. data-dc-screen" resolution order) when
|
|
2134
|
+
// there's no cdId to anchor on.
|
|
2135
|
+
const target = mm.id
|
|
2136
|
+
? resolveSelectionEl(document, { id: mm.id, artboardId: mm.artboardId, index: mm.index })
|
|
2137
|
+
: mm.artboardId
|
|
2138
|
+
? resolveSelectionEl(document, {
|
|
2139
|
+
selector: `[data-dc-screen="${CSS.escape(mm.artboardId)}"]`,
|
|
2140
|
+
})
|
|
2141
|
+
: null;
|
|
2142
|
+
if (target) {
|
|
2143
|
+
selSet.replace(
|
|
2144
|
+
hoverTargetToSelection({
|
|
2145
|
+
el: target,
|
|
2146
|
+
cdId: mm.id,
|
|
2147
|
+
artboardId: mm.artboardId ?? null,
|
|
2148
|
+
} as HoverTarget)
|
|
2149
|
+
);
|
|
2150
|
+
// Task A1 — reveal THROUGH the camera, not host scroll. The old
|
|
2151
|
+
// `scrollIntoView` scrolled the overflow:hidden `.dc-canvas` /
|
|
2152
|
+
// `.dc-artboard-body` clip layers, desyncing the `.dc-world`
|
|
2153
|
+
// transform (Bugs A + B). `revealElementViaCamera` pans the world
|
|
2154
|
+
// the minimal amount only when the element is off-screen.
|
|
2155
|
+
const host = hostRef.current;
|
|
2156
|
+
if (host && zoomController) {
|
|
2157
|
+
revealElementViaCamera(host, target as HTMLElement, zoomController);
|
|
2063
2158
|
}
|
|
2064
2159
|
}
|
|
2065
2160
|
return;
|
|
@@ -2188,13 +2283,57 @@ function CanvasRouter({
|
|
|
2188
2283
|
}
|
|
2189
2284
|
// Shell View-menu chrome toggles + Presentation Mode. Only the fields the
|
|
2190
2285
|
// shell sends are merged, so a `{ present: true }` enter keeps the user's
|
|
2191
|
-
// individual minimap/zoom toggles for the eventual exit.
|
|
2286
|
+
// individual minimap/zoom toggles for the eventual exit. `guides` (T6) is
|
|
2287
|
+
// the odd one out — per-CANVAS persisted state, not a global pref — but
|
|
2288
|
+
// rides the same live-broadcast channel; the shell PATCHes view.json
|
|
2289
|
+
// separately (see setGuidesVisible in app.jsx).
|
|
2192
2290
|
if (m.dgn === 'view-chrome' && chromeCtx) {
|
|
2193
|
-
const mm = m as {
|
|
2194
|
-
|
|
2291
|
+
const mm = m as {
|
|
2292
|
+
minimap?: boolean;
|
|
2293
|
+
zoom?: boolean;
|
|
2294
|
+
present?: boolean;
|
|
2295
|
+
guides?: boolean;
|
|
2296
|
+
print?: boolean;
|
|
2297
|
+
};
|
|
2298
|
+
const patch: {
|
|
2299
|
+
minimap?: boolean;
|
|
2300
|
+
zoom?: boolean;
|
|
2301
|
+
present?: boolean;
|
|
2302
|
+
guides?: boolean;
|
|
2303
|
+
print?: boolean;
|
|
2304
|
+
} = {};
|
|
2195
2305
|
if (typeof mm.minimap === 'boolean') patch.minimap = mm.minimap;
|
|
2196
2306
|
if (typeof mm.zoom === 'boolean') patch.zoom = mm.zoom;
|
|
2197
2307
|
if (typeof mm.present === 'boolean') patch.present = mm.present;
|
|
2308
|
+
if (typeof mm.guides === 'boolean') patch.guides = mm.guides;
|
|
2309
|
+
// feature-2-print-artboards T3 — "Show print guides" (bleed/trim/
|
|
2310
|
+
// margin overlay). Same per-canvas-persisted shape as `guides`.
|
|
2311
|
+
if (typeof mm.print === 'boolean') patch.print = mm.print;
|
|
2312
|
+
// Dogfood follow-up — mirror `guides`/`print` into the in-iframe
|
|
2313
|
+
// `window.__canvas_meta__.overlays` snapshot, exactly like the
|
|
2314
|
+
// existing viewport/layout mirror in canvas-lib.tsx's onSettle (DDR-
|
|
2315
|
+
// 138 comment: "populated ONCE at page load — so after a settle, a
|
|
2316
|
+
// soft HMR remount (any module edit: text, reorder, agent edit)
|
|
2317
|
+
// would re-read the STALE page-load [value]"). Without this, a
|
|
2318
|
+
// structural edit AFTER toggling guides on (e.g. a kind switch,
|
|
2319
|
+
// which is exactly such an edit) remounts DesignCanvasInner, its
|
|
2320
|
+
// `guidesSeededRef` self-seed effect re-fires, and reads the stale
|
|
2321
|
+
// page-load overlays snapshot — silently reverting a live-toggled
|
|
2322
|
+
// guide back to hidden even though the View-menu checkbox still
|
|
2323
|
+
// shows it checked. Same class of bug DDR-138 fixed for the camera;
|
|
2324
|
+
// this is its `overlays` counterpart.
|
|
2325
|
+
if (patch.guides !== undefined || patch.print !== undefined) {
|
|
2326
|
+
const w = window as unknown as {
|
|
2327
|
+
__canvas_meta__?: { overlays?: Record<string, boolean> };
|
|
2328
|
+
};
|
|
2329
|
+
if (w.__canvas_meta__) {
|
|
2330
|
+
w.__canvas_meta__.overlays = {
|
|
2331
|
+
...w.__canvas_meta__.overlays,
|
|
2332
|
+
...(patch.guides !== undefined ? { guides: patch.guides } : {}),
|
|
2333
|
+
...(patch.print !== undefined ? { print: patch.print } : {}),
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2198
2337
|
chromeCtx.setChrome(patch);
|
|
2199
2338
|
return;
|
|
2200
2339
|
}
|