@1agh/maude 0.58.3 → 0.59.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/annotations-layer.tsx +49 -15
- package/apps/studio/bin/_import-asset.mjs +18 -0
- package/apps/studio/bin/_import-figma.mjs +868 -214
- package/apps/studio/bin/_perf-probe-safari.mjs +332 -0
- package/apps/studio/bin/_perf-probe.mjs +228 -0
- package/apps/studio/bin/_perf-shared.mjs +345 -0
- package/apps/studio/bin/_video-playwright.mjs +17 -4
- package/apps/studio/bin/import-figma.sh +10 -1
- package/apps/studio/bin/perf.sh +228 -0
- package/apps/studio/bin/smoke.sh +49 -5
- package/apps/studio/canvas-lib.tsx +148 -6
- package/apps/studio/client/app.jsx +152 -37
- package/apps/studio/client/panels/SyncPanel.jsx +229 -0
- package/apps/studio/client/panels/TimelinePanel.jsx +29 -1
- package/apps/studio/client/panels/timeline-comp-target.js +101 -0
- package/apps/studio/client/styles/3-shell-maude.css +30 -0
- package/apps/studio/client/styles/4-components.css +4 -4
- package/apps/studio/dist/client.bundle.js +772 -772
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/exporters/video-encode-lib.ts +8 -5
- package/apps/studio/exporters/video.ts +10 -0
- package/apps/studio/figma/assets.test.ts +92 -0
- package/apps/studio/figma/assets.ts +63 -9
- package/apps/studio/figma/codegen-client.test.ts +276 -0
- package/apps/studio/figma/codegen-client.ts +509 -0
- package/apps/studio/figma/codegen-fonts.test.ts +103 -0
- package/apps/studio/figma/codegen-fonts.ts +195 -0
- package/apps/studio/figma/codegen-values.test.ts +179 -0
- package/apps/studio/figma/codegen-values.ts +270 -0
- package/apps/studio/figma/endpoints.ts +73 -0
- package/apps/studio/figma/fig-decode.test.ts +702 -0
- package/apps/studio/figma/fig-decode.ts +617 -0
- package/apps/studio/figma/fig-kiwi.ts +410 -0
- package/apps/studio/figma/fig-zip.ts +270 -0
- package/apps/studio/figma/from-codegen.test.ts +408 -0
- package/apps/studio/figma/from-codegen.ts +1103 -0
- package/apps/studio/figma/sanitize.test.ts +69 -0
- package/apps/studio/figma/sanitize.ts +139 -47
- package/apps/studio/figma/tailwind-map.test.ts +142 -0
- package/apps/studio/figma/tailwind-map.ts +545 -0
- package/apps/studio/figma/to-render.ts +25 -3
- package/apps/studio/figma/types.ts +6 -1
- package/apps/studio/http.ts +47 -0
- package/apps/studio/sync/asset-push.ts +346 -38
- package/apps/studio/sync/connection-state.ts +71 -3
- package/apps/studio/sync/index.ts +10 -1
- package/apps/studio/sync/status.ts +18 -0
- package/apps/studio/test/canvas-origin-gate.test.ts +4 -0
- package/apps/studio/test/figma-explode.test.ts +438 -0
- package/apps/studio/test/fixtures/perf-canvas.mjs +201 -0
- package/apps/studio/test/import-figma.test.ts +192 -4
- package/apps/studio/test/sync-asset-push.test.ts +490 -47
- package/apps/studio/test/sync-connection-state.test.ts +66 -0
- package/apps/studio/test/sync-panel-surface.test.ts +90 -0
- package/apps/studio/test/sync-status.test.ts +28 -0
- package/apps/studio/test/timeline-comp-target.test.ts +139 -0
- package/apps/studio/test/video-comp.test.ts +81 -1
- package/apps/studio/test/video-encode-lib.test.ts +63 -0
- package/apps/studio/use-artboard-drag.tsx +37 -3
- package/apps/studio/video-comp.tsx +51 -0
- package/apps/studio/whats-new.json +71 -0
- package/cli/commands/design.mjs +7 -0
- package/cli/commands/kg.mjs +8 -1
- package/cli/commands/kg.test.mjs +24 -0
- package/cli/lib/figma-codegen-reachability.test.mjs +104 -0
- package/cli/lib/figma-import-controls.test.mjs +70 -0
- package/package.json +8 -8
|
@@ -154,7 +154,13 @@ import {
|
|
|
154
154
|
} from './annotations-snap.ts';
|
|
155
155
|
import { arrowPrimitives, type SvgPrimitive } from './canvas-arrowheads.ts';
|
|
156
156
|
import { IconLineThick, IconLineThin } from './canvas-icons.tsx';
|
|
157
|
-
import {
|
|
157
|
+
import {
|
|
158
|
+
countRender,
|
|
159
|
+
getLiveViewport,
|
|
160
|
+
useLiveViewport,
|
|
161
|
+
useViewportControllerContext,
|
|
162
|
+
useWorldRefContext,
|
|
163
|
+
} from './canvas-lib.tsx';
|
|
158
164
|
import { buildAnnotationStrokesRecord } from './commands/annotation-strokes-command.ts';
|
|
159
165
|
import { ensureMenuStyles as ensureCtxMenuStyles } from './context-menu.tsx';
|
|
160
166
|
import { crossedDragThreshold, type Tool } from './input-router.tsx';
|
|
@@ -948,6 +954,7 @@ function scaleStrokeInGroup(
|
|
|
948
954
|
// Component
|
|
949
955
|
|
|
950
956
|
export function AnnotationsLayer() {
|
|
957
|
+
countRender('annotationRenders');
|
|
951
958
|
ensureAnnotStyles();
|
|
952
959
|
const { tool, setTool, sticky, tools, shapeKind } = useToolMode();
|
|
953
960
|
const theme = useCanvasChromeTheme();
|
|
@@ -1011,8 +1018,22 @@ export function AnnotationsLayer() {
|
|
|
1011
1018
|
// endpoint free). Tracked here because endStroke (pointerup) carries no
|
|
1012
1019
|
// modifier state of its own.
|
|
1013
1020
|
const cmdHeldRef = useRef(false);
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1021
|
+
const vpFallbackRef = useRef(vp);
|
|
1022
|
+
vpFallbackRef.current = vp;
|
|
1023
|
+
// Reads the LIVE viewport, not the published one. Publishing is settle-only
|
|
1024
|
+
// (gesture-static React), so mirroring the published value here would freeze
|
|
1025
|
+
// this ref for the whole gesture and every zoom-scaled threshold computed
|
|
1026
|
+
// from it — bind distance, snap tolerance, hit-test slop, sticker placement —
|
|
1027
|
+
// would silently use the pre-gesture zoom. Shaped as a ref so the ~40 existing
|
|
1028
|
+
// `vpRef.current` call sites keep working unchanged.
|
|
1029
|
+
const vpRef = useMemo(
|
|
1030
|
+
() => ({
|
|
1031
|
+
get current() {
|
|
1032
|
+
return getLiveViewport() ?? vpFallbackRef.current;
|
|
1033
|
+
},
|
|
1034
|
+
}),
|
|
1035
|
+
[]
|
|
1036
|
+
);
|
|
1016
1037
|
const visibilityCtx = useAnnotationsVisibility();
|
|
1017
1038
|
const chrome = useChromeVisibility();
|
|
1018
1039
|
// Presentation Mode hides annotations without mutating the user's own
|
|
@@ -1655,7 +1676,9 @@ export function AnnotationsLayer() {
|
|
|
1655
1676
|
|
|
1656
1677
|
const screenToWorld = useCallback(
|
|
1657
1678
|
(cx: number, cy: number): [number, number] => {
|
|
1658
|
-
|
|
1679
|
+
// Live: this runs at event time (drop/placement), where the published
|
|
1680
|
+
// viewport can be a whole gesture behind.
|
|
1681
|
+
const v = vpRef.current ?? { x: 0, y: 0, zoom: 1 };
|
|
1659
1682
|
const z = v.zoom || 1;
|
|
1660
1683
|
return [(cx - v.x) / z, (cy - v.y) / z];
|
|
1661
1684
|
},
|
|
@@ -1826,7 +1849,7 @@ export function AnnotationsLayer() {
|
|
|
1826
1849
|
|
|
1827
1850
|
const eraseAt = useCallback(
|
|
1828
1851
|
(wx: number, wy: number) => {
|
|
1829
|
-
const zoom =
|
|
1852
|
+
const zoom = vpRef.current?.zoom || 1;
|
|
1830
1853
|
const tol = 8 / zoom;
|
|
1831
1854
|
const prev = strokesRef.current;
|
|
1832
1855
|
for (let i = prev.length - 1; i >= 0; i--) {
|
|
@@ -4750,8 +4773,15 @@ function AddTextHint({ strokes, hintId }: { strokes: readonly Stroke[]; hintId:
|
|
|
4750
4773
|
* marquee/drag handler yields).
|
|
4751
4774
|
*/
|
|
4752
4775
|
function ConnectorDots({ stroke }: { stroke: Stroke }) {
|
|
4753
|
-
|
|
4754
|
-
|
|
4776
|
+
// LIVE zoom, deliberately not the published one. These are the counter-scaled
|
|
4777
|
+
// chrome elements (connector dots, selection bbox, section-label chips): they
|
|
4778
|
+
// must hold a constant SCREEN size while the world scales. Publishing is
|
|
4779
|
+
// settle-only since the gesture-static change, so reading published zoom here
|
|
4780
|
+
// would let this chrome grow and shrink with the world through a pinch and
|
|
4781
|
+
// then jump back at settle — the visible fidelity-pop a previous LOD attempt
|
|
4782
|
+
// was reverted for. These components render only for selected/hovered
|
|
4783
|
+
// strokes, so tracking the gesture frame-by-frame stays cheap.
|
|
4784
|
+
const zoom = useLiveViewport().zoom || 1;
|
|
4755
4785
|
if (!isBindable(stroke)) return null;
|
|
4756
4786
|
const center = strokeCenter(stroke);
|
|
4757
4787
|
if (!center) return null;
|
|
@@ -4942,8 +4972,9 @@ function SelectionHalo({
|
|
|
4942
4972
|
anchorsById: Map<string, AnchorHost>;
|
|
4943
4973
|
multi: boolean;
|
|
4944
4974
|
}) {
|
|
4945
|
-
|
|
4946
|
-
|
|
4975
|
+
// Counter-scaled chrome — must hold a constant screen size while the world
|
|
4976
|
+
// scales, so it needs the live zoom, not the settle-cadence published one.
|
|
4977
|
+
const zoom = useLiveViewport().zoom || 1;
|
|
4947
4978
|
const bbox = strokeBBox(stroke, anchorsById);
|
|
4948
4979
|
if (!bbox) return null;
|
|
4949
4980
|
// T17 + post-Wave-2 fix — annotation halo idioms:
|
|
@@ -4990,8 +5021,9 @@ function AnnotGroupBbox({
|
|
|
4990
5021
|
selectedStrokes: readonly Stroke[];
|
|
4991
5022
|
anchorsById: Map<string, AnchorHost>;
|
|
4992
5023
|
}) {
|
|
4993
|
-
|
|
4994
|
-
|
|
5024
|
+
// Counter-scaled chrome — must hold a constant screen size while the world
|
|
5025
|
+
// scales, so it needs the live zoom, not the settle-cadence published one.
|
|
5026
|
+
const zoom = useLiveViewport().zoom || 1;
|
|
4995
5027
|
if (selectedStrokes.length < 2) return null;
|
|
4996
5028
|
let xMin = Number.POSITIVE_INFINITY;
|
|
4997
5029
|
let yMin = Number.POSITIVE_INFINITY;
|
|
@@ -5225,8 +5257,9 @@ function SectionLabelChip({
|
|
|
5225
5257
|
y: number;
|
|
5226
5258
|
hitMode: 'visiblePainted' | 'none';
|
|
5227
5259
|
}) {
|
|
5228
|
-
|
|
5229
|
-
|
|
5260
|
+
// Counter-scaled chrome — must hold a constant screen size while the world
|
|
5261
|
+
// scales, so it needs the live zoom, not the settle-cadence published one.
|
|
5262
|
+
const zoom = useLiveViewport().zoom || 1;
|
|
5230
5263
|
const fontSize = SECTION_LABEL_FONT / zoom;
|
|
5231
5264
|
const chipH = SECTION_LABEL_H / zoom;
|
|
5232
5265
|
const gap = 4 / zoom;
|
|
@@ -5279,8 +5312,9 @@ function SectionTitleEditor({
|
|
|
5279
5312
|
onCommit: (text: string, fmt?: EditorFmt) => void;
|
|
5280
5313
|
onCancel: () => void;
|
|
5281
5314
|
}) {
|
|
5282
|
-
|
|
5283
|
-
|
|
5315
|
+
// Counter-scaled chrome — must hold a constant screen size while the world
|
|
5316
|
+
// scales, so it needs the live zoom, not the settle-cadence published one.
|
|
5317
|
+
const zoom = useLiveViewport().zoom || 1;
|
|
5284
5318
|
const fontSize = SECTION_LABEL_FONT / zoom;
|
|
5285
5319
|
const chipH = SECTION_LABEL_H / zoom;
|
|
5286
5320
|
const gap = 4 / zoom;
|
|
@@ -203,7 +203,25 @@ const ALLOWED_PLAIN_ATTRS = new Set([
|
|
|
203
203
|
'stop-color',
|
|
204
204
|
'stop-opacity',
|
|
205
205
|
'patternUnits',
|
|
206
|
+
// Required by spec for pattern CONTENT, and we were stripping it. A
|
|
207
|
+
// `<pattern>` whose children are authored in the 0..1 unit box — which is what
|
|
208
|
+
// `<use transform="scale(0.00097 0.00075)">` (1/1028 × 1/1331) means — is read
|
|
209
|
+
// in user space without it, so its content collapses to about a pixel.
|
|
210
|
+
//
|
|
211
|
+
// HONEST SCOPE: this is an allowlist bug, NOT the cause of Figma's raster
|
|
212
|
+
// fills failing to appear. That was chased here first and the diagnosis was
|
|
213
|
+
// wrong: Figma's OWN UNTOUCHED export, fetched straight from `/v1/images` and
|
|
214
|
+
// loaded directly, does not paint its `<pattern>`/`<use>`/`<image
|
|
215
|
+
// xlink:href="data:…">` chain either. Allowing this attribute fixes nothing
|
|
216
|
+
// user-visible; it just stops us corrupting a pattern that would otherwise
|
|
217
|
+
// have worked. Same enum-valued, no-URL, no-script risk class as
|
|
218
|
+
// `patternUnits` directly above.
|
|
219
|
+
'patternContentUnits',
|
|
206
220
|
'patternTransform',
|
|
221
|
+
// Presentational text metrics. Their absence is not fatal the way the pattern
|
|
222
|
+
// one is, but it silently drifts imported type away from the source.
|
|
223
|
+
'letter-spacing',
|
|
224
|
+
'xml:space',
|
|
207
225
|
'version',
|
|
208
226
|
]);
|
|
209
227
|
|