@openpresentation/opf-editor 0.17.0 → 0.18.1

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.
@@ -5,7 +5,7 @@ export interface TemplatePanelOptions {
5
5
  editor: EditorSession;
6
6
  /**
7
7
  * Draw the live preview: return the SVG of one slide of `presentation` with `variables` (the values typed so far)
8
- * as an SVG string, or a promise of one. Typically `renderSlideSvg(presentation, slideIndex, { variables, ... })` from
8
+ * as an SVG string, or a promise of one. Typically `toSvg(presentation, slideIndex + 1, { variables, ... })` from
9
9
  * `@openpresentation/opf-render` with the host's fonts. Omit for no preview.
10
10
  */
11
11
  renderPreview?: (input: { presentation: unknown; variables: Record<string, unknown>; slideIndex: number }) => string | Promise<string>;
@@ -67,7 +67,7 @@ export function createTemplatePanel(container, options) {
67
67
  const builtinList = h(doc, "ul", { class: "opf-template-builtin-list" });
68
68
  const builtinSection = h(doc, "details", { class: "opf-template-builtins", "data-opf-component": "template-builtins" },
69
69
  h(doc, "summary", { text: "Built-in variables" }),
70
- h(doc, "p", { class: "opf-template-help", text: "Read from the presentation's own speaker, organization and deck fields; edit those fields to change them. Use them like any variable: {{speaker.name}} inside text, or var:speaker.photo as a whole image field. Slide number, section and slide count vary per slide: write them as {{slide.number}}, {{slide.section}} and {{deck.slideCount}} inside any text, not as a whole var: field." }),
70
+ h(doc, "p", { class: "opf-template-help", text: "Read from the presentation's own speaker, organization and deck fields; edit those fields to change them. Use them like any variable: {{speaker.name}} inside text, or var:speaker.photo as a whole image field. Slide number, section and slide count vary per slide: write them as {{slide.number}}, {{slide.section}} and {{deck.slideCount}} inside any text, not as a whole var: field. The organization logos are images that follow each slide's background (light or dark artwork): place one as a whole image field, for example var:organization.logo.icon in a header or footer zone's image, or choose it with Insert logo." }),
71
71
  builtinList);
72
72
  const live = h(doc, "p", { class: "opf-template-live", role: "status", "aria-live": "polite" });
73
73
  const applyButton = h(doc, "button", { type: "button", class: "opf-template-apply primary", text: "Fill the presentation" });
@@ -230,16 +230,19 @@ export function createTemplatePanel(container, options) {
230
230
  const builtins = listBuiltins(editor.presentation);
231
231
  insertSelect.replaceChildren(
232
232
  ...fields.map((field) => h(doc, "option", { value: field.id, text: `${field.label} (${KIND_LABELS[field.kind]})` })),
233
- ...(builtins.length ? [h(doc, "optgroup", { label: "Built-in variables" }, ...builtins.map((entry) => h(doc, "option", { value: entry.name, text: `${entry.label} (${entry.name})` })))] : []),
233
+ // A slide-scoped image (an organization logo) is a whole-field var: reference, not a {{ }} token for text.
234
+ ...(builtins.length ? [h(doc, "optgroup", { label: "Built-in variables" }, ...builtins.filter((entry) => !(entry.scope === "slide" && entry.kind === "image")).map((entry) => h(doc, "option", { value: entry.name, text: `${entry.label} (${entry.name})` })))] : []),
234
235
  );
235
236
  builtinSection.hidden = !builtins.length;
236
237
  builtinList.replaceChildren(...builtins.map((entry) => {
237
238
  const uses = entry.uses.length;
238
239
  // A slide-scoped built-in has no single value: each slide gets its own when it is drawn or exported (FA-31).
239
240
  const slideScoped = entry.scope === "slide";
240
- const shown = slideScoped ? h(doc, "em", { text: "varies per slide" }) : entry.available ? builtinValueText(entry) : h(doc, "em", { text: "not set" });
241
+ // RR-71: an organization logo is an image placed by var:, and the artwork follows each slide's background.
242
+ const logoImage = slideScoped && entry.kind === "image";
243
+ const shown = logoImage ? h(doc, "em", { text: "image; light or dark artwork per slide" }) : slideScoped ? h(doc, "em", { text: "varies per slide" }) : entry.available ? builtinValueText(entry) : h(doc, "em", { text: "not set" });
241
244
  return h(doc, "li", { "data-builtin": entry.name, "data-kind": entry.kind, "data-scope": entry.scope, "data-available": entry.available ? "true" : "false" },
242
- h(doc, "code", { text: `{{${entry.name}}}` }), ` ${entry.label}: `, shown, slideScoped && !entry.available ? " (no slide has one yet)" : "", uses ? ` (used ${uses} time${uses === 1 ? "" : "s"})` : "");
245
+ h(doc, "code", { text: logoImage ? `var:${entry.name}` : `{{${entry.name}}}` }), ` ${entry.label}: `, shown, slideScoped && !logoImage && !entry.available ? " (no slide has one yet)" : "", logoImage && !entry.available ? " (no logo yet)" : "", uses ? ` (used ${uses} time${uses === 1 ? "" : "s"})` : "");
243
246
  }));
244
247
  slideSelect.replaceChildren(...(editor.presentation.slides ?? []).map((slide, index) => h(doc, "option", { value: String(index), text: `${index + 1}. ${slideTitle(slide) || "Untitled"}` })));
245
248
  previewSlide = Math.min(previewSlide, Math.max(0, (editor.presentation.slides?.length ?? 1) - 1));
package/dist/templates.js CHANGED
@@ -8,7 +8,7 @@ import { OPFEditorError, getValueAtPath, opfPathToJsonPointer } from "./index.js
8
8
 
9
9
  const VARIABLE_ID = /^[a-z][a-z0-9-]*$/;
10
10
  // A built-in variable name (core FA-04): `speakers`, or deck/speaker/organization plus one or two dotted segments.
11
- const BUILTIN_NAME = /^(?:speakers|(?:deck|slide|speaker|organization)(?:\.[A-Za-z0-9_-]+){1,2})$/;
11
+ const BUILTIN_NAME = /^(?:speakers|(?:deck|slide|speaker|organization)(?:\.[A-Za-z0-9_-]+){1,3})$/;
12
12
  const KINDS = ["color", "text", "number", "date", "image", "url", "list"];
13
13
 
14
14
  /** The form control each variable kind uses. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpresentation/opf-editor",
3
- "version": "0.17.0",
3
+ "version": "0.18.1",
4
4
  "description": "Embeddable local OPF editor primitives built on the deterministic renderer.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -257,12 +257,12 @@
257
257
  "@codemirror/search": "6.7.2",
258
258
  "@codemirror/state": "6.7.6",
259
259
  "@codemirror/view": "6.43.13",
260
- "@lezer/highlight": "1.2.4",
261
- "@openpresentation/opf": "^0.17.0",
260
+ "@lezer/highlight": "1.2.5",
261
+ "@openpresentation/opf": "^0.18.3",
262
262
  "jsonc-parser": "3.3.1"
263
263
  },
264
264
  "peerDependencies": {
265
- "@openpresentation/opf-render": "^0.17.0"
265
+ "@openpresentation/opf-render": "^0.18.1"
266
266
  },
267
267
  "peerDependenciesMeta": {
268
268
  "@openpresentation/opf-render": {
@@ -274,8 +274,8 @@
274
274
  "@expo-google-fonts/caladea": "0.4.2",
275
275
  "@expo-google-fonts/cousine": "0.4.3",
276
276
  "@expo-google-fonts/gelasio": "0.4.1",
277
- "@expo-google-fonts/noto-color-emoji": "0.4.6",
278
- "@expo-google-fonts/noto-emoji": "0.4.7",
277
+ "@expo-google-fonts/noto-color-emoji": "0.4.7",
278
+ "@expo-google-fonts/noto-emoji": "0.4.8",
279
279
  "@expo-google-fonts/noto-naskh-arabic": "0.4.5",
280
280
  "@expo-google-fonts/noto-nastaliq-urdu": "0.4.2",
281
281
  "@expo-google-fonts/noto-sans": "0.4.2",
@@ -288,23 +288,23 @@
288
288
  "@expo-google-fonts/noto-sans-gujarati": "0.4.2",
289
289
  "@expo-google-fonts/noto-sans-gurmukhi": "0.4.1",
290
290
  "@expo-google-fonts/noto-sans-hebrew": "0.4.1",
291
- "@expo-google-fonts/noto-sans-jp": "0.4.3",
291
+ "@expo-google-fonts/noto-sans-jp": "0.4.4",
292
292
  "@expo-google-fonts/noto-sans-kannada": "0.4.3",
293
293
  "@expo-google-fonts/noto-sans-khmer": "0.4.3",
294
- "@expo-google-fonts/noto-sans-kr": "0.4.3",
294
+ "@expo-google-fonts/noto-sans-kr": "0.4.4",
295
295
  "@expo-google-fonts/noto-sans-lao": "0.4.2",
296
296
  "@expo-google-fonts/noto-sans-malayalam": "0.4.2",
297
297
  "@expo-google-fonts/noto-sans-math": "0.4.2",
298
298
  "@expo-google-fonts/noto-sans-mongolian": "0.4.1",
299
299
  "@expo-google-fonts/noto-sans-myanmar": "0.4.2",
300
300
  "@expo-google-fonts/noto-sans-oriya": "0.4.2",
301
- "@expo-google-fonts/noto-sans-sc": "0.4.3",
301
+ "@expo-google-fonts/noto-sans-sc": "0.4.4",
302
302
  "@expo-google-fonts/noto-sans-sinhala": "0.4.2",
303
303
  "@expo-google-fonts/noto-sans-symbols": "0.4.1",
304
304
  "@expo-google-fonts/noto-sans-symbols-2": "0.4.1",
305
305
  "@expo-google-fonts/noto-sans-syriac": "0.4.2",
306
306
  "@expo-google-fonts/noto-sans-tamil": "0.4.3",
307
- "@expo-google-fonts/noto-sans-tc": "0.4.3",
307
+ "@expo-google-fonts/noto-sans-tc": "0.4.4",
308
308
  "@expo-google-fonts/noto-sans-telugu": "0.4.2",
309
309
  "@expo-google-fonts/noto-sans-thaana": "0.4.2",
310
310
  "@expo-google-fonts/noto-sans-thai": "0.4.2",
@@ -314,13 +314,14 @@
314
314
  "@expo-google-fonts/roboto-mono": "0.4.2",
315
315
  "@expo-google-fonts/stix-two-math": "0.4.0",
316
316
  "@expo-google-fonts/tinos": "0.4.2",
317
- "@openpresentation/opf-pptx": "^0.17.0",
318
- "@openpresentation/opf-render": "^0.17.0",
319
- "axe-core": "4.13.0",
317
+ "@openpresentation/opf-pptx": "^0.18.1",
318
+ "@openpresentation/opf-render": "^0.18.1",
319
+ "@resvg/resvg-js": "2.6.2",
320
+ "axe-core": "4.14.0",
320
321
  "esbuild": "0.28.2",
321
322
  "jszip": "3.10.2",
322
323
  "pdf-lib": "1.17.1",
323
- "pdfjs-dist": "6.3.289",
324
+ "pdfjs-dist": "6.4.299",
324
325
  "playwright": "1.63.0"
325
326
  }
326
327
  }