diff --git a/crates/ui-egui/locales/bn.toml b/crates/ui-egui/locales/bn.toml index 364c9632..c3453096 100644 --- a/crates/ui-egui/locales/bn.toml +++ b/crates/ui-egui/locales/bn.toml @@ -304,7 +304,6 @@ status = "draft — needs native review" "Constraints" = "সীমাবদ্ধতা (Constraints)" "Content" = "কন্টেন্ট" "Contents hidden" = "কন্টেন্ট লুকানো আছে" -"Contents only" = "শুধু কন্টেন্ট" "Contextual alternates" = "প্রসঙ্গভিত্তিক বিকল্প" "Contrast" = "কনট্রাস্ট (Contrast)" "Contributors" = "অবদানকারীগণ" @@ -628,6 +627,7 @@ status = "draft — needs native review" "If" = "যদি (If)" "If {condition}" = "যদি {condition}" "Ignore auto layout (absolute position)" = "অটো লেআউট উপেক্ষা করুন (অ্যাবসোলিউট পজিশন)" +"Ignore overlapping layers" = "ওভারল্যাপ করা লেয়ার উপেক্ষা করুন" "Image" = "ছবি" "Images" = "ছবিসমূহ" "Import" = "ইম্পোর্ট" diff --git a/crates/ui-egui/locales/cs.toml b/crates/ui-egui/locales/cs.toml index 8fe5fe3b..139a195a 100644 --- a/crates/ui-egui/locales/cs.toml +++ b/crates/ui-egui/locales/cs.toml @@ -295,7 +295,6 @@ status = "draft — needs native review" "Constraints" = "Omezení" "Content" = "Obsah" "Contents hidden" = "Obsah skryt" -"Contents only" = "Pouze obsah" "Contextual alternates" = "Kontextové alternativy" "Contrast" = "Kontrast" "Contributors" = "Přispěvatelé" @@ -613,6 +612,7 @@ status = "draft — needs native review" "If" = "Pokud" "If {condition}" = "Pokud {condition}" "Ignore auto layout (absolute position)" = "Ignorovat automatické rozvržení (absolutní poloha)" +"Ignore overlapping layers" = "Ignorovat překrývající se vrstvy" "Image" = "Obrázek" "Images" = "Obrázky" "Import" = "Import" diff --git a/crates/ui-egui/locales/de.toml b/crates/ui-egui/locales/de.toml index 26470631..dbdcab51 100644 --- a/crates/ui-egui/locales/de.toml +++ b/crates/ui-egui/locales/de.toml @@ -291,7 +291,6 @@ status = "draft — needs native review" "Constraints" = "Constraints" "Content" = "Inhalt" "Contents hidden" = "Inhalt ausgeblendet" -"Contents only" = "Nur Inhalt" "Contextual alternates" = "Kontextbedingte Varianten" "Contrast" = "Kontrast" "Contributors" = "Mitwirkende" @@ -600,6 +599,7 @@ status = "draft — needs native review" "If" = "Wenn" "If {condition}" = "Wenn {condition}" "Ignore auto layout (absolute position)" = "Auto-Layout ignorieren (absolute Position)" +"Ignore overlapping layers" = "Überlappende Ebenen ignorieren" "Image" = "Bild" "Images" = "Bilder" "Import" = "Importieren" diff --git a/crates/ui-egui/locales/en.toml b/crates/ui-egui/locales/en.toml index 38da48ba..bc61086e 100644 --- a/crates/ui-egui/locales/en.toml +++ b/crates/ui-egui/locales/en.toml @@ -305,7 +305,6 @@ name = "English" "Constraints" = "Constraints" "Content" = "Content" "Contents hidden" = "Contents hidden" -"Contents only" = "Contents only" "Contextual alternates" = "Contextual alternates" "Contrast" = "Contrast" "Contributors" = "Contributors" @@ -632,6 +631,7 @@ name = "English" "If" = "If" "If {condition}" = "If {condition}" "Ignore auto layout (absolute position)" = "Ignore auto layout (absolute position)" +"Ignore overlapping layers" = "Ignore overlapping layers" "Image" = "Image" "Images" = "Images" "Import" = "Import" diff --git a/crates/ui-egui/locales/es.toml b/crates/ui-egui/locales/es.toml index 9c0c73e8..0eec9808 100644 --- a/crates/ui-egui/locales/es.toml +++ b/crates/ui-egui/locales/es.toml @@ -305,7 +305,6 @@ status = "draft — needs native review" "Constraints" = "Restricciones" "Content" = "Contenido" "Contents hidden" = "Contenido oculto" -"Contents only" = "Solo el contenido" "Contextual alternates" = "Alternativas contextuales" "Contrast" = "Contraste" "Contributors" = "Colaboradores" @@ -632,6 +631,7 @@ status = "draft — needs native review" "If" = "Si" "If {condition}" = "Si {condition}" "Ignore auto layout (absolute position)" = "Ignorar diseño automático (posición absoluta)" +"Ignore overlapping layers" = "Ignorar capas superpuestas" "Image" = "Imagen" "Images" = "Imágenes" "Import" = "Importar" diff --git a/crates/ui-egui/locales/fi.toml b/crates/ui-egui/locales/fi.toml index a3b6dcc0..635b501f 100644 --- a/crates/ui-egui/locales/fi.toml +++ b/crates/ui-egui/locales/fi.toml @@ -303,7 +303,6 @@ status = "draft — needs native review" "Constraints" = "Rajoitteet" "Content" = "Sisältö" "Contents hidden" = "Sisältö kätketty" -"Contents only" = "Vain sisältö" "Contextual alternates" = "Kontekstuaaliset vaihtoehdot" "Contrast" = "Kontrasti" "Contributors" = "Tekijät" @@ -630,6 +629,7 @@ status = "draft — needs native review" "If it keeps happening, please report it at {link} with this message." = "Jos ongelma jatkuu, ilmoita siitä osoitteessa {link} ja liitä tämä viesti mukaan." "If {condition}" = "Jos {condition}" "Ignore auto layout (absolute position)" = "Ohita automaattinen asettelu (absoluuttinen sijainti)" +"Ignore overlapping layers" = "Ohita päällekkäiset tasot" "Image" = "Kuva" "Images" = "Kuvat" "Import" = "Tuo" diff --git a/crates/ui-egui/locales/fr.toml b/crates/ui-egui/locales/fr.toml index 1fb7d57a..b8d64b43 100644 --- a/crates/ui-egui/locales/fr.toml +++ b/crates/ui-egui/locales/fr.toml @@ -301,7 +301,6 @@ status = "draft — needs native review" "Constraints" = "Contraintes" "Content" = "Contenu" "Contents hidden" = "Contenu masqué" -"Contents only" = "Contenu uniquement" "Contextual alternates" = "Variantes contextuelles" "Contrast" = "Contraste" "Contributors" = "Contributeurs" @@ -629,6 +628,7 @@ status = "draft — needs native review" "If" = "Si" "If {condition}" = "Si {condition}" "Ignore auto layout (absolute position)" = "Ignorer la mise en page auto (position absolue)" +"Ignore overlapping layers" = "Ignorer les calques superposés" "Image" = "Image" "Images" = "Images" "Import" = "Importer" diff --git a/crates/ui-egui/locales/id.toml b/crates/ui-egui/locales/id.toml index bb46c68a..601cb2c3 100644 --- a/crates/ui-egui/locales/id.toml +++ b/crates/ui-egui/locales/id.toml @@ -299,7 +299,6 @@ status = "draft — needs native review" "Constraints" = "Batasan" "Content" = "Konten" "Contents hidden" = "Konten disembunyikan" -"Contents only" = "Hanya konten" "Contextual alternates" = "Alternatif kontekstual" "Contrast" = "Kontras" "Contributors" = "Kontributor" @@ -617,6 +616,7 @@ status = "draft — needs native review" "If" = "Jika" "If {condition}" = "Jika {condition}" "Ignore auto layout (absolute position)" = "Abaikan auto layout (posisi absolut)" +"Ignore overlapping layers" = "Abaikan layer yang tumpang tindih" "Image" = "Gambar" "Images" = "Gambar" "Import" = "Impor" diff --git a/crates/ui-egui/locales/ja.toml b/crates/ui-egui/locales/ja.toml index 5d5b9fe1..3fc535ae 100644 --- a/crates/ui-egui/locales/ja.toml +++ b/crates/ui-egui/locales/ja.toml @@ -302,7 +302,6 @@ status = "draft — needs native review" "Constraints" = "制約" "Content" = "コンテンツ" "Contents hidden" = "コンテンツ非表示" -"Contents only" = "コンテンツのみ" "Contextual alternates" = "前後関係に依存する字形" "Contrast" = "コントラスト" "Contributors" = "貢献者" @@ -624,6 +623,7 @@ status = "draft — needs native review" "If" = "条件" "If {condition}" = "条件:{condition}" "Ignore auto layout (absolute position)" = "オートレイアウトを無視(絶対位置)" +"Ignore overlapping layers" = "重なっているレイヤーを無視" "Image" = "画像" "Images" = "画像" "Import" = "インポート" diff --git a/crates/ui-egui/locales/ka.toml b/crates/ui-egui/locales/ka.toml index af06d1bf..eefb2dd3 100644 --- a/crates/ui-egui/locales/ka.toml +++ b/crates/ui-egui/locales/ka.toml @@ -306,7 +306,6 @@ status = "draft — reviewed by a native speaker, awaiting a maintainer's approv "Constraints" = "შეზღუდვები" "Content" = "შიგთავსი" "Contents hidden" = "შიგთავსი დამალულია" -"Contents only" = "მხოლოდ შიგთავსი" "Contextual alternates" = "კონტექსტური ალტერნატივები" "Contrast" = "კონტრასტი" "Contributors" = "მონაწილეები" @@ -630,6 +629,7 @@ status = "draft — reviewed by a native speaker, awaiting a maintainer's approv "If" = "თუ" "If {condition}" = "თუ {condition}" "Ignore auto layout (absolute position)" = "ავტოგანლაგების იგნორირება (აბსოლუტური პოზიცია)" +"Ignore overlapping layers" = "გადაფარული შრეების იგნორირება" "Image" = "გამოსახულება" "Images" = "გამოსახულებები" "Import" = "იმპორტი" diff --git a/crates/ui-egui/locales/ko.toml b/crates/ui-egui/locales/ko.toml index 29383ce9..35e5a59a 100644 --- a/crates/ui-egui/locales/ko.toml +++ b/crates/ui-egui/locales/ko.toml @@ -291,7 +291,6 @@ status = "draft — needs native review" "Constraints" = "제약" "Content" = "콘텐츠" "Contents hidden" = "콘텐츠 숨김" -"Contents only" = "콘텐츠만" "Contextual alternates" = "문맥 대체 글자" "Contrast" = "대비" "Contributors" = "기여자" @@ -596,6 +595,7 @@ status = "draft — needs native review" "If" = "조건" "If {condition}" = "조건: {condition}" "Ignore auto layout (absolute position)" = "자동 레이아웃 무시(절대 위치)" +"Ignore overlapping layers" = "겹치는 레이어 무시" "Image" = "이미지" "Images" = "이미지" "Import" = "가져오기" diff --git a/crates/ui-egui/locales/nl.toml b/crates/ui-egui/locales/nl.toml index 46fc575a..484909ea 100644 --- a/crates/ui-egui/locales/nl.toml +++ b/crates/ui-egui/locales/nl.toml @@ -303,7 +303,6 @@ status = "draft — needs native review" "Constraints" = "Constraints" "Content" = "Inhoud" "Contents hidden" = "Inhoud verborgen" -"Contents only" = "Alleen de inhoud" "Contextual alternates" = "Contextuele alternatieven" "Contrast" = "Contrast" "Contributors" = "Bijdragers" @@ -630,6 +629,7 @@ status = "draft — needs native review" "If it keeps happening, please report it at {link} with this message." = "Als dit blijft gebeuren, meld het dan op {link} met dit bericht." "If {condition}" = "Als {condition}" "Ignore auto layout (absolute position)" = "Auto layout negeren (absolute positie)" +"Ignore overlapping layers" = "Overlappende lagen negeren" "Image" = "Afbeelding" "Images" = "Afbeeldingen" "Import" = "Importeren" diff --git a/crates/ui-egui/locales/pl.toml b/crates/ui-egui/locales/pl.toml index d90e7a1a..a7dbfff0 100644 --- a/crates/ui-egui/locales/pl.toml +++ b/crates/ui-egui/locales/pl.toml @@ -302,7 +302,6 @@ status = "draft — needs native review" "Constraints" = "Więzy" "Content" = "Zawartość" "Contents hidden" = "Zawartość ukryta" -"Contents only" = "Tylko zawartość" "Contextual alternates" = "Alternatywy kontekstowe" "Contrast" = "Kontrast" "Contributors" = "Współtwórcy" @@ -627,6 +626,7 @@ status = "draft — needs native review" "If" = "Jeżeli" "If {condition}" = "Jeżeli {condition}" "Ignore auto layout (absolute position)" = "Ignoruj automatyczny układ (pozycja bezwzględna)" +"Ignore overlapping layers" = "Ignoruj nakładające się warstwy" "Image" = "Obraz" "Images" = "Obrazy" "Import" = "Importuj" diff --git a/crates/ui-egui/locales/pt-BR.toml b/crates/ui-egui/locales/pt-BR.toml index 0ec91f10..ece93fbd 100644 --- a/crates/ui-egui/locales/pt-BR.toml +++ b/crates/ui-egui/locales/pt-BR.toml @@ -289,7 +289,6 @@ status = "draft — needs native review" "Constraints" = "Restrições" "Content" = "Conteúdo" "Contents hidden" = "Conteúdo oculto" -"Contents only" = "Somente o conteúdo" "Contextual alternates" = "Alternativas contextuais" "Contrast" = "Contraste" "Contributors" = "Colaboradores" @@ -595,6 +594,7 @@ status = "draft — needs native review" "If" = "Se" "If {condition}" = "Se {condition}" "Ignore auto layout (absolute position)" = "Ignorar layout automático (posição absoluta)" +"Ignore overlapping layers" = "Ignorar camadas sobrepostas" "Image" = "Imagem" "Images" = "Imagens" "Import" = "Importar" diff --git a/crates/ui-egui/locales/ru.toml b/crates/ui-egui/locales/ru.toml index 71efff90..1635123c 100644 --- a/crates/ui-egui/locales/ru.toml +++ b/crates/ui-egui/locales/ru.toml @@ -302,7 +302,6 @@ name = "Русский" "Constraints" = "Ограничения" "Content" = "Содержимое" "Contents hidden" = "Содержимое скрыто" -"Contents only" = "Только содержимое" "Contextual alternates" = "Контекстные альтернативы" "Contrast" = "Контраст" "Contributors" = "Участники" @@ -629,6 +628,7 @@ name = "Русский" "If it keeps happening, please report it at {link} with this message." = "Если это повторяется, сообщите об этом по адресу {link}, приложив это сообщение." "If {condition}" = "Если {condition}" "Ignore auto layout (absolute position)" = "Игнорировать автолейаут (абсолютная позиция)" +"Ignore overlapping layers" = "Игнорировать перекрывающиеся слои" "Image" = "Изображение" "Images" = "Изображения" "Import" = "Импорт" diff --git a/crates/ui-egui/locales/sv.toml b/crates/ui-egui/locales/sv.toml index 25823103..e4fff1a7 100644 --- a/crates/ui-egui/locales/sv.toml +++ b/crates/ui-egui/locales/sv.toml @@ -299,7 +299,6 @@ name = "Svenska" "Constraints" = "Begränsningar" "Content" = "Innehåll" "Contents hidden" = "Innehållet är dolt" -"Contents only" = "Endast innehåll" "Contextual alternates" = "Kontextuella alternativ" "Contrast" = "Kontrast" "Contributors" = "Bidragsgivare" @@ -624,6 +623,7 @@ name = "Svenska" "If" = "Om" "If {condition}" = "Om {condition}" "Ignore auto layout (absolute position)" = "Ignorera automatisk layout (absolut position)" +"Ignore overlapping layers" = "Ignorera överlappande lager" "Image" = "Bild" "Images" = "Bilder" "Import" = "Importera" diff --git a/crates/ui-egui/locales/tr.toml b/crates/ui-egui/locales/tr.toml index 0fe26b89..fbb1f661 100644 --- a/crates/ui-egui/locales/tr.toml +++ b/crates/ui-egui/locales/tr.toml @@ -299,7 +299,6 @@ name = "Türkçe" "Constraints" = "Kısıtlamalar" "Content" = "İçerik" "Contents hidden" = "İçerik gizli" -"Contents only" = "Yalnızca içerik" "Contextual alternates" = "Bağlamsal alternatifler" "Contrast" = "Kontrast" "Contributors" = "Katkıda bulunanlar" @@ -617,6 +616,7 @@ name = "Türkçe" "If" = "Eğer" "If {condition}" = "Eğer {condition}" "Ignore auto layout (absolute position)" = "Otomatik yerleşimi yok say (mutlak konum)" +"Ignore overlapping layers" = "Çakışan katmanları yok say" "Image" = "Görüntü" "Images" = "Görüntüler" "Import" = "İçe aktar" diff --git a/crates/ui-egui/locales/zh-Hans.toml b/crates/ui-egui/locales/zh-Hans.toml index 5fddecc6..acebfc76 100644 --- a/crates/ui-egui/locales/zh-Hans.toml +++ b/crates/ui-egui/locales/zh-Hans.toml @@ -292,7 +292,6 @@ status = "draft — needs native review" "Constraints" = "约束" "Content" = "内容" "Contents hidden" = "内容已隐藏" -"Contents only" = "仅内容" "Contextual alternates" = "上下文替代字" "Contrast" = "对比度" "Contributors" = "贡献者" @@ -597,6 +596,7 @@ status = "draft — needs native review" "If" = "如果" "If {condition}" = "如果 {condition}" "Ignore auto layout (absolute position)" = "忽略自动布局(绝对定位)" +"Ignore overlapping layers" = "忽略重叠图层" "Image" = "图片" "Images" = "图片" "Import" = "导入" diff --git a/crates/ui-egui/src/export_panel.rs b/crates/ui-egui/src/export_panel.rs index 8617c35a..5e05cc19 100644 --- a/crates/ui-egui/src/export_panel.rs +++ b/crates/ui-egui/src/export_panel.rs @@ -40,8 +40,9 @@ pub fn section(app: &mut FigApp, ui: &mut Ui, doc: &Document, sel: &[NodeId]) { if mixed { widgets::note(ui, tr("Click + to replace mixed content"), t.text_secondary); } + let text = sel.iter().all(|i| matches!(doc.node(*i).map(|n| &n.kind), Some(NodeKind::Text(_)))); for (i, e) in list.iter().enumerate() { - setting_row(app, ui, &ids, i, e); + setting_row(app, ui, &ids, i, e, text); } let jobs = export_jobs(doc, sel); if jobs.is_empty() { @@ -61,8 +62,9 @@ pub fn section(app: &mut FigApp, ui: &mut Ui, doc: &Document, sel: &[NodeId]) { } /// One export setting: size (typed or picked; images only, SVG and PDF are vector), suffix, -/// format, advanced options and remove; a PDF's print settings under it. -fn setting_row(app: &mut FigApp, ui: &mut Ui, ids: &[NodeId], i: usize, e: &ExportSetting) { +/// format, advanced options and remove; a PDF's print settings under it. `text`: every layer in +/// `ids` is a text layer. +fn setting_row(app: &mut FigApp, ui: &mut Ui, ids: &[NodeId], i: usize, e: &ExportSetting, text: bool) { row(ui, 32.0, |ui| { // Tighter spacing so the advanced options and remove buttons fit beside the fields. ui.spacing_mut().item_spacing.x = 4.0; @@ -98,7 +100,7 @@ fn setting_row(app: &mut FigApp, ui: &mut Ui, ids: &[NodeId], i: usize, e: &Expo .width(216.0) .close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside) .show(|ui| { - if let Some(mut params) = advanced_options(ui, e) { + if let Some(mut params) = advanced_options(ui, e, text) { params["ids"] = json!(ids); params["index"] = json!(i); app.run("export.update", params); @@ -113,17 +115,21 @@ fn setting_row(app: &mut FigApp, ui: &mut Ui, ids: &[NodeId], i: usize, e: &Expo } } -/// A setting's advanced options: contents only and include bounding box, and for SVG outline -/// text, the id attribute and simplified strokes. Returns the changed option as command params. -fn advanced_options(ui: &mut Ui, e: &ExportSetting) -> Option { +/// A setting's advanced options: ignore overlapping layers (`contentsOnly`), include bounding box +/// for text layers (and for any setting that has it on, so it can be turned off), and for SVG +/// outline text, the id attribute and simplified strokes. Returns the changed option as command +/// params. +fn advanced_options(ui: &mut Ui, e: &ExportSetting, text: bool) -> Option { let mut out = None; let mut option = |ui: &mut Ui, key: &str, on: bool, label: &str| { if widgets::checkbox(ui, on, label) { out = Some(json!({ key: !on })); } }; - option(ui, "contentsOnly", e.contents_only, tr("Contents only")); - option(ui, "includeBoundingBox", e.include_bounding_box, tr("Include bounding box")); + option(ui, "contentsOnly", e.contents_only, tr("Ignore overlapping layers")); + if text || e.include_bounding_box { + option(ui, "includeBoundingBox", e.include_bounding_box, tr("Include bounding box")); + } if e.format == ExportFormat::Svg { option(ui, "svgOutlineText", e.svg_outline_text, tr("Outline text")); option(ui, "svgIdAttribute", e.svg_id_attribute, tr("Include id attribute")); diff --git a/crates/ui-egui/src/export_preview_tests.rs b/crates/ui-egui/src/export_preview_tests.rs index 468a5f17..f888ab47 100644 --- a/crates/ui-egui/src/export_preview_tests.rs +++ b/crates/ui-egui/src/export_preview_tests.rs @@ -1,7 +1,7 @@ //! The Export section's Preview row: a slice paints nothing itself, so its preview must show the //! page content under it — the same thing exporting the slice writes — and not a blank //! transparency checkerboard next to a correct export. And its setting rows: a size only for -//! images. +//! images, and advanced options named as the reference app names them. use figcraft_doc::{Document, NodeId}; use figcraft_engine::Session; @@ -93,3 +93,33 @@ fn export_rows_offer_a_size_for_images_only() { assert!(size_menu(&u), "{format} has sizes again"); } } + +/// The advanced options: Ignore overlapping layers (the `contentsOnly` setting), and Include +/// bounding box for text layers only. A setting that already has the bounding box on keeps it, and +/// the option stays so it can be turned off. +#[test] +fn advanced_options_offer_the_bounding_box_for_text_layers() { + let mut s = Session::new(); + let r = crate::present_tests::id(&s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 100, "height": 80})).unwrap()); + let t = crate::present_tests::id(&s.execute("text.create", &json!({"text": "Hi", "x": 200, "y": 0})).unwrap()); + s.execute("export.add", &json!({"ids": [r]})).unwrap(); + s.execute("export.add", &json!({"ids": [t]})).unwrap(); + let mut u = crate::layers_drag_tests::Ui::new(s); + let options = |u: &mut crate::layers_drag_tests::Ui, id: NodeId| { + u.app.run("select.set", json!({"ids": [id]})); + u.frame(vec![]); + egui::Popup::open_id(&u.ctx, egui::Id::new(("export_more", 0))); + u.frame(vec![]); + crate::import_report_tests::shown_texts(u.frame_output(vec![]).shapes) + }; + let shown = options(&mut u, r); + assert!(shown.iter().any(|s| s == "Ignore overlapping layers"), "the reference app's name: {shown:?}"); + assert!(!shown.iter().any(|s| s == "Contents only")); + assert!(!shown.iter().any(|s| s == "Include bounding box"), "a rectangle has no bounding box option"); + let shown = options(&mut u, t); + assert!(shown.iter().any(|s| s == "Include bounding box"), "a text layer has it: {shown:?}"); + u.app.run("export.update", json!({"ids": [r], "index": 0, "includeBoundingBox": true})); + let shown = options(&mut u, r); + assert!(shown.iter().any(|s| s == "Include bounding box"), "a rectangle that has it on shows it: {shown:?}"); + assert!(u.app.session.doc().unwrap().node(r).unwrap().exports[0].include_bounding_box, "the setting is kept"); +} diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index b7cab725..88a92c7c 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -423,7 +423,7 @@ Hours in this narrative are the builders' estimates; the tables above supersede presenter) and variables (the local variables JSON passed along, next to the file or embedded: collections, modes, aliases, scopes, layer bindings and explicit modes). Export panel: a row per export setting (typed or preset sizes like `2x` / `512w` / `512h`, PNG, - JPG, WebP, SVG and PDF, suffix, advanced options: contents only, include bounding box, and for + JPG, WebP, SVG and PDF, suffix, advanced options: ignore overlapping layers, include bounding box for text layers, and for SVG outline text, id attributes and simplified strokes), a preview, and "Export N layers" (`file.exportLayers`) in the panel and the Export dialog. Paste from other apps: images, SVG and text (the newest clipboard content wins over our own copy; pasted SVG lands centred in the view), and layers copied from