@agent-native/core 0.131.3 → 0.131.5

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.
Files changed (60) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/docs/content/docs-components.mdx +491 -0
  4. package/corpus/core/package.json +1 -1
  5. package/corpus/core/src/client/AgentPanel.tsx +58 -34
  6. package/corpus/core/src/localization/default-messages.ts +6 -0
  7. package/corpus/templates/content/.agents/skills/content-product-development/SKILL.md +47 -0
  8. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +3 -1
  9. package/corpus/templates/design/actions/get-design.ts +11 -3
  10. package/corpus/templates/design/actions/present-design-variants.ts +62 -5
  11. package/corpus/templates/design/app/components/design/BreakpointBar.tsx +64 -1
  12. package/corpus/templates/design/app/components/design/EditPanel.tsx +199 -25
  13. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +160 -46
  14. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -1
  15. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +59 -12
  16. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +1 -1
  17. package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +34 -29
  18. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +2 -2
  19. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +28 -10
  20. package/corpus/templates/design/app/components/design/inspector/design-icons.tsx +15 -28
  21. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +4 -3
  22. package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +12 -8
  23. package/corpus/templates/design/app/components/design/multi-screen/culling.ts +34 -9
  24. package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +13 -27
  25. package/corpus/templates/design/app/components/design/multi-screen/types.ts +8 -1
  26. package/corpus/templates/design/app/components/design/multi-screen/zoom-gesture.ts +95 -0
  27. package/corpus/templates/design/app/i18n-data.ts +121 -10
  28. package/corpus/templates/design/app/pages/design-editor/data-operations.ts +45 -0
  29. package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +59 -0
  30. package/corpus/templates/design/app/pages/design-editor/text-edit-utils.ts +115 -40
  31. package/corpus/templates/design/changelog/2026-07-28-generated-design-variants-no-longer-overlap-each-other-on-th.md +6 -0
  32. package/corpus/templates/design/changelog/2026-07-29-auto-layout-direction-icons-show-an-arrow.md +6 -0
  33. package/corpus/templates/design/changelog/2026-07-29-breakpoints-no-longer-overlap-neighbouring-screens.md +6 -0
  34. package/corpus/templates/design/changelog/2026-07-29-canvas-is-more-responsive-when-selecting-and-adding-frames.md +6 -0
  35. package/corpus/templates/design/changelog/2026-07-29-canvas-zoom-is-smoother-and-labels-hold-their-size.md +6 -0
  36. package/corpus/templates/design/changelog/2026-07-29-double-click-a-frame-now-drills-into-its-layers.md +6 -0
  37. package/corpus/templates/design/changelog/2026-07-29-export-preview-shows-the-real-render.md +6 -0
  38. package/corpus/templates/design/changelog/2026-07-29-figma-parity-shortcuts.md +6 -0
  39. package/corpus/templates/design/changelog/2026-07-29-more-breakpoint-width-presets.md +6 -0
  40. package/corpus/templates/design/changelog/2026-07-29-resize-a-selected-frame-to-a-device-preset.md +6 -0
  41. package/corpus/templates/design/changelog/2026-07-29-text-tool-reaches-the-right-surface.md +6 -0
  42. package/corpus/templates/design/shared/canvas-frames.ts +23 -0
  43. package/corpus/templates/design/shared/code-layer.ts +54 -2
  44. package/corpus/templates/design/shared/responsive-frame-layout.ts +55 -0
  45. package/dist/client/AgentPanel.d.ts.map +1 -1
  46. package/dist/client/AgentPanel.js +16 -5
  47. package/dist/client/AgentPanel.js.map +1 -1
  48. package/dist/localization/default-messages.d.ts +6 -0
  49. package/dist/localization/default-messages.d.ts.map +1 -1
  50. package/dist/localization/default-messages.js +6 -0
  51. package/dist/localization/default-messages.js.map +1 -1
  52. package/dist/notifications/routes.d.ts +1 -1
  53. package/dist/observability/routes.d.ts +3 -3
  54. package/dist/progress/routes.d.ts +1 -1
  55. package/dist/resources/handlers.d.ts +1 -1
  56. package/dist/server/transcribe-voice.d.ts +1 -1
  57. package/docs/content/docs-components.mdx +491 -0
  58. package/package.json +1 -1
  59. package/src/client/AgentPanel.tsx +58 -34
  60. package/src/localization/default-messages.ts +6 -0
@@ -90,7 +90,8 @@ const enUS = {
90
90
  pageHelpDescription:
91
91
  "Edit typography, spacing, sizing, borders and fill for whatever you select. Page defaults below.",
92
92
  sections: {
93
- page: "Page",
93
+ page: "Screen",
94
+ canvas: "Canvas",
94
95
  typography: "Typography",
95
96
  autoLayout: "Auto layout",
96
97
  positionLayout: "Position",
@@ -145,6 +146,9 @@ const enUS = {
145
146
  shadow: "Shadow",
146
147
  filter: "Filter",
147
148
  addLayer: "Add layer",
149
+ addFill: "Add fill",
150
+ addStroke: "Add stroke",
151
+ addEffect: "Add effect",
148
152
  removeLayer: "Remove layer",
149
153
  showLayer: "Show layer",
150
154
  hideLayer: "Hide layer",
@@ -364,8 +368,13 @@ const enUS = {
364
368
  dotted: "Dotted",
365
369
  double: "Double",
366
370
  },
371
+ exportPreview: {
372
+ rendering: "Rendering preview…",
373
+ failed: "Preview unavailable",
374
+ },
367
375
  framePresets: {
368
376
  title: "Frame",
377
+ applyToFrame: "Resize to preset",
369
378
  categories: {
370
379
  phone: "Phone",
371
380
  tablet: "Tablet",
@@ -1154,6 +1163,8 @@ const enUS = {
1154
1163
  },
1155
1164
  },
1156
1165
  multiScreenCanvas: {
1166
+ addBreakpointToAllScreens:
1167
+ "Add {{label}} breakpoint ({{width}}px) to all screens",
1157
1168
  duplicate: "Duplicate",
1158
1169
  fork: "Fork",
1159
1170
  fullView: "Full view",
@@ -1718,7 +1729,8 @@ const designLocaleOverrides = {
1718
1729
  pageHelpDescription:
1719
1730
  "编辑您选择的任何版式、间距、大小、边框和填充。页面默认如下。",
1720
1731
  sections: {
1721
- page: "",
1732
+ page: "画面",
1733
+ canvas: "画布",
1722
1734
  typography: "版式",
1723
1735
  flexLayout: "弹性布局",
1724
1736
  layout: "布局",
@@ -2119,7 +2131,8 @@ const designLocaleOverrides = {
2119
2131
  pageHelpDescription:
2120
2132
  "Edite tipografía, espaciado, tamaño, bordes y rellene lo que seleccione. Valores predeterminados de página a continuación.",
2121
2133
  sections: {
2122
- page: "Página",
2134
+ page: "Pantalla",
2135
+ canvas: "Lienzo",
2123
2136
  typography: "Tipografía",
2124
2137
  flexLayout: "Diseño flexible",
2125
2138
  layout: "Disposición",
@@ -2541,7 +2554,8 @@ const designLocaleOverrides = {
2541
2554
  pageHelpDescription:
2542
2555
  "Modifiez la typographie, l'espacement, le dimensionnement, les bordures et remplissez ce que vous sélectionnez. Valeurs par défaut de la page ci-dessous.",
2543
2556
  sections: {
2544
- page: "Page",
2557
+ page: "Écran",
2558
+ canvas: "Canevas",
2545
2559
  typography: "Typographie",
2546
2560
  flexLayout: "Disposition flexible",
2547
2561
  layout: "Mise en page",
@@ -2967,7 +2981,8 @@ const designLocaleOverrides = {
2967
2981
  pageHelpDescription:
2968
2982
  "Bearbeiten Sie Typografie, Abstände, Größen, Ränder und Füllung für alles, was Sie auswählen. Seitenstandards unten.",
2969
2983
  sections: {
2970
- page: "Seite",
2984
+ page: "Screen",
2985
+ canvas: "Arbeitsfläche",
2971
2986
  typography: "Typografie",
2972
2987
  flexLayout: "Flex-Layout",
2973
2988
  layout: "Layout",
@@ -3394,7 +3409,8 @@ const designLocaleOverrides = {
3394
3409
  pageHelpDescription:
3395
3410
  "選択した内容のタイポグラフィ、間隔、サイズ、境界線、塗りつぶしを編集します。ページのデフォルトは以下です。",
3396
3411
  sections: {
3397
- page: "ページ",
3412
+ page: "画面",
3413
+ canvas: "キャンバス",
3398
3414
  typography: "タイポグラフィ",
3399
3415
  flexLayout: "フレックスレイアウト",
3400
3416
  layout: "レイアウト",
@@ -3816,7 +3832,8 @@ const designLocaleOverrides = {
3816
3832
  pageHelpDescription:
3817
3833
  "선택한 항목에 대해 타이포그래피, 간격, 크기, 테두리 및 채우기를 편집하세요. 아래는 페이지 기본값입니다.",
3818
3834
  sections: {
3819
- page: "페이지",
3835
+ page: "화면",
3836
+ canvas: "캔버스",
3820
3837
  typography: "타이포그래피",
3821
3838
  flexLayout: "플렉스 레이아웃",
3822
3839
  layout: "공들여 나열한 것",
@@ -4231,7 +4248,8 @@ const designLocaleOverrides = {
4231
4248
  pageHelpDescription:
4232
4249
  "Edite tipografia, espaçamento, dimensionamento, bordas e preenchimento de acordo com o que você selecionar. Padrões de página abaixo.",
4233
4250
  sections: {
4234
- page: "Página",
4251
+ page: "Tela",
4252
+ canvas: "Tela de trabalho",
4235
4253
  typography: "Tipografia",
4236
4254
  flexLayout: "Layout flexível",
4237
4255
  layout: "Disposição",
@@ -4653,7 +4671,8 @@ const designLocaleOverrides = {
4653
4671
  pageHelpDescription:
4654
4672
  "टाइपोग्राफी, रिक्ति, आकार, सीमाएँ संपादित करें और जो भी आप चुनें उसे भरें। पृष्ठ डिफ़ॉल्ट नीचे है.",
4655
4673
  sections: {
4656
- page: "पेज",
4674
+ page: "स्क्रीन",
4675
+ canvas: "कैनवास",
4657
4676
  typography: "टाइपोग्राफी",
4658
4677
  flexLayout: "फ्लेक्स लेआउट",
4659
4678
  layout: "लेआउट",
@@ -5066,7 +5085,8 @@ const designLocaleOverrides = {
5066
5085
  pageHelpDescription:
5067
5086
  "تحرير الطباعة، والتباعد، والتحجيم، والحدود وملء ما تحدده. الإعدادات الافتراضية للصفحة أدناه.",
5068
5087
  sections: {
5069
- page: "صفحة",
5088
+ page: "الشاشة",
5089
+ canvas: "لوحة الرسم",
5070
5090
  typography: "الطباعة",
5071
5091
  flexLayout: "تخطيط مرن",
5072
5092
  layout: "تَخطِيط",
@@ -7889,6 +7909,8 @@ const designModeFeatureOverrides = {
7889
7909
  },
7890
7910
  },
7891
7911
  multiScreenCanvas: {
7912
+ addBreakpointToAllScreens:
7913
+ "為所有畫面新增 {{label}} 中斷點({{width}}px)",
7892
7914
  duplicate: "複製",
7893
7915
  fork: "分支",
7894
7916
  fullView: "完整檢視",
@@ -8059,6 +8081,7 @@ const designModeFeatureOverrides = {
8059
8081
  },
8060
8082
  },
8061
8083
  multiScreenCanvas: {
8084
+ addBreakpointToAllScreens: "为所有画面添加 {{label}} 断点({{width}}px)",
8062
8085
  duplicate: "复制",
8063
8086
  fork: "分支",
8064
8087
  fullView: "完整视图",
@@ -8230,6 +8253,8 @@ const designModeFeatureOverrides = {
8230
8253
  },
8231
8254
  },
8232
8255
  multiScreenCanvas: {
8256
+ addBreakpointToAllScreens:
8257
+ "Añadir punto de ruptura {{label}} ({{width}}px) a todas las pantallas",
8233
8258
  duplicate: "Duplicar",
8234
8259
  fork: "Bifurcar",
8235
8260
  fullView: "Vista completa",
@@ -8422,6 +8447,8 @@ const designModeFeatureOverrides = {
8422
8447
  },
8423
8448
  },
8424
8449
  multiScreenCanvas: {
8450
+ addBreakpointToAllScreens:
8451
+ "Ajouter le point de rupture {{label}} ({{width}}px) à tous les écrans",
8425
8452
  duplicate: "Dupliquer",
8426
8453
  fork: "Créer une branche",
8427
8454
  fullView: "Vue complète",
@@ -8611,6 +8638,8 @@ const designModeFeatureOverrides = {
8611
8638
  },
8612
8639
  },
8613
8640
  multiScreenCanvas: {
8641
+ addBreakpointToAllScreens:
8642
+ "{{label}}-Breakpoint ({{width}}px) zu allen Screens hinzufügen",
8614
8643
  duplicate: "Duplizieren",
8615
8644
  fork: "Abzweigen",
8616
8645
  fullView: "Vollansicht",
@@ -8805,6 +8834,8 @@ const designModeFeatureOverrides = {
8805
8834
  },
8806
8835
  },
8807
8836
  multiScreenCanvas: {
8837
+ addBreakpointToAllScreens:
8838
+ "すべての画面に {{label}} ブレークポイント({{width}}px)を追加",
8808
8839
  duplicate: "複製",
8809
8840
  fork: "分岐",
8810
8841
  fullView: "全体表示",
@@ -8994,6 +9025,8 @@ const designModeFeatureOverrides = {
8994
9025
  },
8995
9026
  },
8996
9027
  multiScreenCanvas: {
9028
+ addBreakpointToAllScreens:
9029
+ "모든 화면에 {{label}} 중단점({{width}}px) 추가",
8997
9030
  duplicate: "복제",
8998
9031
  fork: "분기",
8999
9032
  fullView: "전체 보기",
@@ -9180,6 +9213,8 @@ const designModeFeatureOverrides = {
9180
9213
  },
9181
9214
  },
9182
9215
  multiScreenCanvas: {
9216
+ addBreakpointToAllScreens:
9217
+ "Adicionar ponto de quebra {{label}} ({{width}}px) a todas as telas",
9183
9218
  duplicate: "Duplicar",
9184
9219
  fork: "Ramificar",
9185
9220
  fullView: "Vista completa",
@@ -9366,6 +9401,8 @@ const designModeFeatureOverrides = {
9366
9401
  },
9367
9402
  },
9368
9403
  multiScreenCanvas: {
9404
+ addBreakpointToAllScreens:
9405
+ "सभी स्क्रीन में {{label}} ब्रेकपॉइंट ({{width}}px) जोड़ें",
9369
9406
  duplicate: "डुप्लिकेट",
9370
9407
  fork: "फोर्क",
9371
9408
  fullView: "पूर्ण दृश्य",
@@ -9552,6 +9589,8 @@ const designModeFeatureOverrides = {
9552
9589
  },
9553
9590
  },
9554
9591
  multiScreenCanvas: {
9592
+ addBreakpointToAllScreens:
9593
+ "إضافة نقطة توقف {{label}} ({{width}}px) إلى جميع الشاشات",
9555
9594
  duplicate: "تكرار",
9556
9595
  fork: "تفريع",
9557
9596
  fullView: "عرض كامل",
@@ -9695,6 +9734,9 @@ const designCanvasFeatureOverrides = {
9695
9734
  editPanel: {
9696
9735
  labels: {
9697
9736
  addLayer: "新增图层",
9737
+ addFill: "添加填充",
9738
+ addStroke: "添加描边",
9739
+ addEffect: "添加效果",
9698
9740
  removeLayer: "移除图层",
9699
9741
  showLayer: "显示图层",
9700
9742
  hideLayer: "隐藏图层",
@@ -9795,6 +9837,9 @@ const designCanvasFeatureOverrides = {
9795
9837
  editPanel: {
9796
9838
  labels: {
9797
9839
  addLayer: "Añadir capa",
9840
+ addFill: "Añadir relleno",
9841
+ addStroke: "Añadir trazo",
9842
+ addEffect: "Añadir efecto",
9798
9843
  removeLayer: "Eliminar capa",
9799
9844
  showLayer: "Mostrar capa",
9800
9845
  hideLayer: "Ocultar capa",
@@ -9897,6 +9942,9 @@ const designCanvasFeatureOverrides = {
9897
9942
  editPanel: {
9898
9943
  labels: {
9899
9944
  addLayer: "Ajouter un calque",
9945
+ addFill: "Ajouter un remplissage",
9946
+ addStroke: "Ajouter un contour",
9947
+ addEffect: "Ajouter un effet",
9900
9948
  removeLayer: "Supprimer le calque",
9901
9949
  showLayer: "Afficher le calque",
9902
9950
  hideLayer: "Masquer le calque",
@@ -9999,6 +10047,9 @@ const designCanvasFeatureOverrides = {
9999
10047
  editPanel: {
10000
10048
  labels: {
10001
10049
  addLayer: "Ebene hinzufügen",
10050
+ addFill: "Füllung hinzufügen",
10051
+ addStroke: "Kontur hinzufügen",
10052
+ addEffect: "Effekt hinzufügen",
10002
10053
  removeLayer: "Ebene entfernen",
10003
10054
  showLayer: "Ebene anzeigen",
10004
10055
  hideLayer: "Ebene ausblenden",
@@ -10097,6 +10148,9 @@ const designCanvasFeatureOverrides = {
10097
10148
  editPanel: {
10098
10149
  labels: {
10099
10150
  addLayer: "レイヤーを追加",
10151
+ addFill: "塗りを追加",
10152
+ addStroke: "線を追加",
10153
+ addEffect: "エフェクトを追加",
10100
10154
  removeLayer: "レイヤーを削除",
10101
10155
  showLayer: "レイヤーを表示",
10102
10156
  hideLayer: "レイヤーを非表示",
@@ -10195,6 +10249,9 @@ const designCanvasFeatureOverrides = {
10195
10249
  editPanel: {
10196
10250
  labels: {
10197
10251
  addLayer: "레이어 추가",
10252
+ addFill: "칠 추가",
10253
+ addStroke: "선 추가",
10254
+ addEffect: "효과 추가",
10198
10255
  removeLayer: "레이어 제거",
10199
10256
  showLayer: "레이어 표시",
10200
10257
  hideLayer: "레이어 숨기기",
@@ -10295,6 +10352,9 @@ const designCanvasFeatureOverrides = {
10295
10352
  editPanel: {
10296
10353
  labels: {
10297
10354
  addLayer: "Adicionar camada",
10355
+ addFill: "Adicionar preenchimento",
10356
+ addStroke: "Adicionar contorno",
10357
+ addEffect: "Adicionar efeito",
10298
10358
  removeLayer: "Remover camada",
10299
10359
  showLayer: "Mostrar camada",
10300
10360
  hideLayer: "Ocultar camada",
@@ -10393,6 +10453,9 @@ const designCanvasFeatureOverrides = {
10393
10453
  editPanel: {
10394
10454
  labels: {
10395
10455
  addLayer: "परत जोड़ें",
10456
+ addFill: "भराव जोड़ें",
10457
+ addStroke: "स्ट्रोक जोड़ें",
10458
+ addEffect: "प्रभाव जोड़ें",
10396
10459
  removeLayer: "परत हटाएं",
10397
10460
  showLayer: "परत दिखाएं",
10398
10461
  hideLayer: "परत छिपाएं",
@@ -10491,6 +10554,9 @@ const designCanvasFeatureOverrides = {
10491
10554
  editPanel: {
10492
10555
  labels: {
10493
10556
  addLayer: "إضافة طبقة",
10557
+ addFill: "إضافة تعبئة",
10558
+ addStroke: "إضافة حدود",
10559
+ addEffect: "إضافة تأثير",
10494
10560
  removeLayer: "إزالة طبقة",
10495
10561
  showLayer: "إظهار الطبقة",
10496
10562
  hideLayer: "إخفاء الطبقة",
@@ -13312,8 +13378,13 @@ const designFillStylesComingSoonOverrides = {
13312
13378
  const designFramePresetsOverrides = {
13313
13379
  "zh-CN": {
13314
13380
  editPanel: {
13381
+ exportPreview: {
13382
+ rendering: "正在生成预览…",
13383
+ failed: "无法生成预览",
13384
+ },
13315
13385
  framePresets: {
13316
13386
  title: "画框",
13387
+ applyToFrame: "调整为预设尺寸",
13317
13388
  categories: {
13318
13389
  phone: "手机",
13319
13390
  tablet: "平板",
@@ -13329,8 +13400,13 @@ const designFramePresetsOverrides = {
13329
13400
  },
13330
13401
  "es-ES": {
13331
13402
  editPanel: {
13403
+ exportPreview: {
13404
+ rendering: "Generando vista previa…",
13405
+ failed: "Vista previa no disponible",
13406
+ },
13332
13407
  framePresets: {
13333
13408
  title: "Marco",
13409
+ applyToFrame: "Cambiar a tamaño predefinido",
13334
13410
  categories: {
13335
13411
  phone: "Teléfono",
13336
13412
  tablet: "Tableta",
@@ -13346,8 +13422,13 @@ const designFramePresetsOverrides = {
13346
13422
  },
13347
13423
  "fr-FR": {
13348
13424
  editPanel: {
13425
+ exportPreview: {
13426
+ rendering: "Génération de l'aperçu…",
13427
+ failed: "Aperçu indisponible",
13428
+ },
13349
13429
  framePresets: {
13350
13430
  title: "Cadre",
13431
+ applyToFrame: "Redimensionner selon un préréglage",
13351
13432
  categories: {
13352
13433
  phone: "Téléphone",
13353
13434
  tablet: "Tablette",
@@ -13363,8 +13444,13 @@ const designFramePresetsOverrides = {
13363
13444
  },
13364
13445
  "de-DE": {
13365
13446
  editPanel: {
13447
+ exportPreview: {
13448
+ rendering: "Vorschau wird erstellt…",
13449
+ failed: "Vorschau nicht verfügbar",
13450
+ },
13366
13451
  framePresets: {
13367
13452
  title: "Rahmen",
13453
+ applyToFrame: "Auf Voreinstellung anpassen",
13368
13454
  categories: {
13369
13455
  phone: "Telefon",
13370
13456
  tablet: "Tablet",
@@ -13380,8 +13466,13 @@ const designFramePresetsOverrides = {
13380
13466
  },
13381
13467
  "ja-JP": {
13382
13468
  editPanel: {
13469
+ exportPreview: {
13470
+ rendering: "プレビューを生成中…",
13471
+ failed: "プレビューを表示できません",
13472
+ },
13383
13473
  framePresets: {
13384
13474
  title: "フレーム",
13475
+ applyToFrame: "プリセットサイズに変更",
13385
13476
  categories: {
13386
13477
  phone: "電話",
13387
13478
  tablet: "タブレット",
@@ -13397,8 +13488,13 @@ const designFramePresetsOverrides = {
13397
13488
  },
13398
13489
  "ko-KR": {
13399
13490
  editPanel: {
13491
+ exportPreview: {
13492
+ rendering: "미리 보기 생성 중…",
13493
+ failed: "미리 보기를 사용할 수 없음",
13494
+ },
13400
13495
  framePresets: {
13401
13496
  title: "프레임",
13497
+ applyToFrame: "사전 설정 크기로 조정",
13402
13498
  categories: {
13403
13499
  phone: "휴대폰",
13404
13500
  tablet: "태블릿",
@@ -13414,8 +13510,13 @@ const designFramePresetsOverrides = {
13414
13510
  },
13415
13511
  "pt-BR": {
13416
13512
  editPanel: {
13513
+ exportPreview: {
13514
+ rendering: "Gerando pré-visualização…",
13515
+ failed: "Pré-visualização indisponível",
13516
+ },
13417
13517
  framePresets: {
13418
13518
  title: "Quadro",
13519
+ applyToFrame: "Redimensionar para predefinição",
13419
13520
  categories: {
13420
13521
  phone: "Celular",
13421
13522
  tablet: "Tablet",
@@ -13431,8 +13532,13 @@ const designFramePresetsOverrides = {
13431
13532
  },
13432
13533
  "hi-IN": {
13433
13534
  editPanel: {
13535
+ exportPreview: {
13536
+ rendering: "पूर्वावलोकन बन रहा है…",
13537
+ failed: "पूर्वावलोकन उपलब्ध नहीं",
13538
+ },
13434
13539
  framePresets: {
13435
13540
  title: "फ़्रेम",
13541
+ applyToFrame: "प्रीसेट आकार में बदलें",
13436
13542
  categories: {
13437
13543
  phone: "फ़ोन",
13438
13544
  tablet: "टैबलेट",
@@ -13448,8 +13554,13 @@ const designFramePresetsOverrides = {
13448
13554
  },
13449
13555
  "ar-SA": {
13450
13556
  editPanel: {
13557
+ exportPreview: {
13558
+ rendering: "جارٍ إنشاء المعاينة…",
13559
+ failed: "المعاينة غير متوفرة",
13560
+ },
13451
13561
  framePresets: {
13452
13562
  title: "الإطار",
13563
+ applyToFrame: "تغيير الحجم إلى إعداد مسبق",
13453
13564
  categories: {
13454
13565
  phone: "الهاتف",
13455
13566
  tablet: "الجهاز اللوحي",
@@ -2,6 +2,7 @@ import type {
2
2
  CanvasFrameGeometry,
3
3
  CanvasFrameGeometryById,
4
4
  } from "@shared/canvas-frames";
5
+ import { parseCssColor } from "@shared/color-utils";
5
6
 
6
7
  export const KEEPALIVE_ACTION_MAX_BYTES = 60_000;
7
8
 
@@ -47,6 +48,50 @@ function valuesEqual(left: unknown, right: unknown): boolean {
47
48
  return JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
48
49
  }
49
50
 
51
+ /** Accepts a canvas background only if it parses as a CSS colour. It is
52
+ * interpolated into a style attribute, so an arbitrary string is an injection
53
+ * vector — this gates both the persisted value and any in-flight draft. */
54
+ export function sanitizeCanvasBackground(value: unknown): string | null {
55
+ if (typeof value !== "string") return null;
56
+ const trimmed = value.trim();
57
+ if (!trimmed) return null;
58
+ return parseCssColor(trimmed) ? trimmed : null;
59
+ }
60
+
61
+ /** Design-level canvas background, or null when unset/unsafe. */
62
+ export function getDesignCanvasBackground(
63
+ designData: Record<string, unknown> | null | undefined,
64
+ ): string | null {
65
+ if (!isRecord(designData)) return null;
66
+ return sanitizeCanvasBackground(designData.canvasBackground);
67
+ }
68
+
69
+ /** Breakpoint widths persisted on the design, ascending and de-duplicated.
70
+ * Reads the live design data rather than a screen's mirrored copy so callers
71
+ * running after a mutation see what is actually stored. */
72
+ export function getDesignBreakpointWidths(
73
+ designData: Record<string, unknown> | null | undefined,
74
+ ): number[] {
75
+ if (!isRecord(designData)) return [];
76
+ const breakpointSet = designData.breakpointSet;
77
+ if (!isRecord(breakpointSet)) return [];
78
+ const breakpoints = breakpointSet.breakpoints;
79
+ if (!Array.isArray(breakpoints)) return [];
80
+ const widths = new Set<number>();
81
+ for (const entry of breakpoints) {
82
+ if (!isRecord(entry)) continue;
83
+ const widthPx = entry.widthPx;
84
+ if (
85
+ typeof widthPx === "number" &&
86
+ Number.isFinite(widthPx) &&
87
+ widthPx > 0
88
+ ) {
89
+ widths.add(widthPx);
90
+ }
91
+ }
92
+ return [...widths].sort((a, b) => a - b);
93
+ }
94
+
50
95
  export function viewportSizeFromFrameGeometry(
51
96
  geometry: CanvasFrameGeometry | undefined,
52
97
  ): { width: number; height: number } | null {
@@ -109,6 +109,65 @@ export function computeDistributedPositions(
109
109
  return next;
110
110
  }
111
111
 
112
+ /** One screen's own frame box plus the footprint its responsive row occupies. */
113
+ export interface ReflowCandidate {
114
+ id: string;
115
+ /** Resolved frame geometry, including screens with no persisted entry yet. */
116
+ geometry: { x: number; y: number; width: number; height: number };
117
+ /** Space actually painted, breakpoint frames included. */
118
+ footprint: AlignableRect;
119
+ }
120
+
121
+ function footprintsOverlap(rects: readonly AlignableRect[]): boolean {
122
+ return rects.some((a, i) =>
123
+ rects.some(
124
+ (b, j) =>
125
+ i !== j &&
126
+ a.x < b.x + b.width &&
127
+ b.x < a.x + a.width &&
128
+ a.y < b.y + b.height &&
129
+ b.y < a.y + a.height,
130
+ ),
131
+ );
132
+ }
133
+
134
+ /**
135
+ * Re-packs a board whose responsive rows have grown into each other, returning
136
+ * complete geometry per screen — including screens that had no persisted entry
137
+ * and were positioned by `getInitialFrameGeometry`. Returning only the moved
138
+ * x/y would drop those screens at the write-back, which is exactly the
139
+ * default-layout board that needs the reflow most.
140
+ *
141
+ * Empty when there is nothing to do, so a deliberately arranged,
142
+ * non-overlapping board is never rearranged.
143
+ */
144
+ export function computeOverlapReflowGeometry(
145
+ candidates: readonly ReflowCandidate[],
146
+ ): Map<string, { x: number; y: number; width: number; height: number }> {
147
+ const result = new Map<
148
+ string,
149
+ { x: number; y: number; width: number; height: number }
150
+ >();
151
+ if (candidates.length < 2) return result;
152
+ const footprints = candidates.map((candidate) => candidate.footprint);
153
+ if (!footprintsOverlap(footprints)) return result;
154
+ const positions = computeTidyPositions(footprints);
155
+ if (positions.size === 0) return result;
156
+ for (const candidate of candidates) {
157
+ const position = positions.get(candidate.id);
158
+ if (!position) continue;
159
+ // Translate by the footprint's delta rather than adopting the packed origin
160
+ // as the frame origin. A rotated group's AABB origin is not its frame
161
+ // origin, so assigning it directly shifts the frame by the rotation offset.
162
+ result.set(candidate.id, {
163
+ ...candidate.geometry,
164
+ x: candidate.geometry.x + (position.x - candidate.footprint.x),
165
+ y: candidate.geometry.y + (position.y - candidate.footprint.y),
166
+ });
167
+ }
168
+ return result;
169
+ }
170
+
112
171
  export function computeTidyPositions(
113
172
  rects: readonly AlignableRect[],
114
173
  ): Map<string, { x: number; y: number }> {