@openpresentation/opf-editor 0.20.4 → 0.22.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/README.md +5 -2
- package/dist/design-controls.js +5 -2
- package/dist/table-options.d.ts +1 -1
- package/dist/table-options.js +4 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -110,6 +110,8 @@ Chart options (RR-35): `@openpresentation/opf-editor/chart-options` edits a char
|
|
|
110
110
|
|
|
111
111
|
Chart highlight (FA-14): the same module edits `chart.highlight`: `setChartOptions(editor, chartPath, { highlight: { series: ["Revenue"], categories: ["Q3"] } })` replaces each listed part (an empty list removes it, `null` removes the field), refuses a name the chart does not have, and writes only what the chart type can highlight (core `chartOptionSupport(...).highlight`). `readChartOptions(chart, document)` returns the `choices` (plotted series and category labels, resolved through the document for a dataset chart), and the panel lists them as two groups of checkboxes ("Highlight series", "Highlight categories").
|
|
112
112
|
|
|
113
|
+
Chart colors (known gap): core 0.21 added `chart.colors` (a position-matched list of series or category colors, as a hex color, a scheme slot or a role), and opf-pptx 0.22.0 exports it (the opf-render preview follows once opf-render#256 lands), but the editor has no control for it yet. The chart options panel edits `highlight` as its only color-related setting (the two checkbox groups above), and `setChartOptions` does not accept `colors`. Until a control exists, set `chart.colors` in the document directly (the JSON control or a patch).
|
|
114
|
+
|
|
113
115
|
```js
|
|
114
116
|
import { createCanvasEditor } from '@openpresentation/opf-editor/canvas';
|
|
115
117
|
import { saveDocument } from '@openpresentation/opf-editor';
|
|
@@ -431,9 +433,10 @@ setTableStyle(editor, "slides.4.blocks.1.table", "banded"); //
|
|
|
431
433
|
mergeTableCells(editor, "slides.4.blocks.1.table", { section: "body", row: 1, column: 0 }, { colSpan: 3 });
|
|
432
434
|
splitTableCell(editor, "slides.4.blocks.1.table", { section: "body", row: 1, column: 0 });
|
|
433
435
|
setTableCellStyle(editor, "slides.4.blocks.1.table", [{ section: "header", column: 0 }], { fill: "accent", align: "center" });
|
|
436
|
+
setTableCellStyle(editor, "slides.4.blocks.1.table", { section: "body", row: 2, column: 3 }, { bold: true }); // a bold number cell keeps its column format and alignment; { bold: null } removes it
|
|
434
437
|
```
|
|
435
438
|
|
|
436
|
-
Styles use scheme roles, so they follow the color scheme, and the renderers keep the text readable on any fill. A style sets the header fill (`theme`, `plain`, `accent`), banded rows and borders (`theme`, `none`, `horizontal`, `grid`); named presets are `theme`, `banded`, `grid`, `minimal` and `open`, and `theme` removes a previous style. A style owns only the fill and border fields of a cell: text color, alignment, padding, values and merges are kept. Merging never hides text: covered cells that hold text refuse with `merge-would-lose-content` unless you pass `join: true`, which joins the words into the anchor with a space and keeps run formatting. Other refusals are `merge-overlap` (the region crosses another merge), `invalid-table-span` (outside the table, or a header cell spanning into the body) and `table-cell-covered`. Splitting leaves the formerly covered cells as empty text. `parseTableCellPath` maps a canvas selection to a table and cell, and `describeTableCell` and `readTableStyle` read the current state.
|
|
439
|
+
Styles use scheme roles, so they follow the color scheme, and the renderers keep the text readable on any fill. A style sets the header fill (`theme`, `plain`, `accent`), banded rows and borders (`theme`, `none`, `horizontal`, `grid`); named presets are `theme`, `banded`, `grid`, `minimal` and `open`, and `theme` removes a previous style. A style owns only the fill and border fields of a cell: text color, alignment, bold, padding, values and merges are kept. To bold one cell, set `bold: true` on its style with `setTableCellStyle` (the panel's Bold checkbox does): the cell stays a plain value in a numeric column, so it keeps the column's number `format` and alignment, which rich runs would drop (needs core with `TableCellStyle.bold`). Merging never hides text: covered cells that hold text refuse with `merge-would-lose-content` unless you pass `join: true`, which joins the words into the anchor with a space and keeps run formatting. Other refusals are `merge-overlap` (the region crosses another merge), `invalid-table-span` (outside the table, or a header cell spanning into the body) and `table-cell-covered`. Splitting leaves the formerly covered cells as empty text. `parseTableCellPath` maps a canvas selection to a table and cell, and `describeTableCell` and `readTableStyle` read the current state.
|
|
437
440
|
|
|
438
441
|
Table alt text (FA-27): `setTableAlt(editor, tablePath, { alt: "North America leads EMEA in Q4." })` writes the table's text alternative (`Table.alt`) as one undoable patch, like a chart's. `alt` is trimmed and an empty string or `null` removes it; `{ decorative: true }` writes the empty alt (decorative, and it wins over `alt`) and `{ decorative: false }` removes an empty alt. It works on a table that shows a shared dataset too, since the alt belongs to the table and not to its data. `readTableAlt(table)` gives `{ alt, decorative }` for a form and `prepareTableAlt` is the headless patch. The table section of the design controls has an "Alt text" field and a "Decorative (no alt text)" box, and find and replace searches `table.alt`. `validate` does not ask for a table alt, so the field is optional.
|
|
439
442
|
|
|
@@ -521,7 +524,7 @@ const selectionControls = createDesignControls(contentPanel, { editor, getSlideI
|
|
|
521
524
|
controls.refresh(); // when the slide or the selection changes
|
|
522
525
|
```
|
|
523
526
|
|
|
524
|
-
Sections: `look` (theme, color scheme, font scheme, language, this slide's layout), `background` (type, theme slot, solid color, gradient with its stops, image with fit, focus, alt text, recolor and overlay, any of the 54 patterns, opacity; a draft until Apply, with Remove), `header-footer` (choose header or footer and a zone, then every part the zone supports: a text box with an "Insert value" menu that puts the slide number, slide count, section, organization, speaker or deck name at the cursor as a `{{ }}` variable (Enter commits, Shift+Enter starts a new line), an image with an "Insert logo" action (a shape and, for several organizations, an organization; it writes the logo reference as the zone's image), social profiles, and the current or fixed date and format, with a summary of the zones in use), `brand` (the organization logo: one image for every shape, or each of the four shapes for both, light and dark backgrounds, for the organization you choose; which organization's logo and shape covers, sections and picture bullets draw, or none; picture bullets, accent font, watermark), `layout-options` (alignment, direction, primary chart, content box, default image fit), `info` (narrative, tone, audience, socials), `selection` (content type with a loss report, list levels, group of metrics, group and ungroup, image to background or watermark, replacement, chart type), `image` (the selected image block's fit, focus, shape, corner radius, border, opacity, recolor, overlay, aspect ratio and placement), `catalog` (reference findings and the explicit "Update from catalog"), `slide-content` (blocks to regions and back, design images back into the content) and `table` (style, merge, split, cell fill and
|
|
527
|
+
Sections: `look` (theme, color scheme, font scheme, language, this slide's layout), `background` (type, theme slot, solid color, gradient with its stops, image with fit, focus, alt text, recolor and overlay, any of the 54 patterns, opacity; a draft until Apply, with Remove), `header-footer` (choose header or footer and a zone, then every part the zone supports: a text box with an "Insert value" menu that puts the slide number, slide count, section, organization, speaker or deck name at the cursor as a `{{ }}` variable (Enter commits, Shift+Enter starts a new line), an image with an "Insert logo" action (a shape and, for several organizations, an organization; it writes the logo reference as the zone's image), social profiles, and the current or fixed date and format, with a summary of the zones in use), `brand` (the organization logo: one image for every shape, or each of the four shapes for both, light and dark backgrounds, for the organization you choose; which organization's logo and shape covers, sections and picture bullets draw, or none; picture bullets, accent font, watermark), `layout-options` (alignment, direction, primary chart, content box, default image fit), `info` (narrative, tone, audience, socials), `selection` (content type with a loss report, list levels, group of metrics, group and ungroup, image to background or watermark, replacement, chart type), `image` (the selected image block's fit, focus, shape, corner radius, border, opacity, recolor, overlay, aspect ratio and placement), `catalog` (reference findings and the explicit "Update from catalog"), `slide-content` (blocks to regions and back, design images back into the content) and `table` (style, merge, split, cell fill, alignment and bold). The panel is native `details`, `fieldset`, `select`, checkbox and text controls with a label on each, so it works with the keyboard and with screen readers: groups open with Enter or Space, a select changes with the arrow keys, text fields commit on Enter or when you leave them, and results and refusals are announced in `role="status"` and `role="alert"` regions. A refused change (an invalid value, text a merge would hide) is explained, changes nothing, and puts the field back. "Applies to" switches the design controls between the whole presentation and the current slide, and a control shows when a slide value is "set on this slide" or "from the presentation". The panel offers only conversions that exist, shows what a conversion loses before you choose it, and lists why an unavailable one is unavailable.
|
|
525
528
|
|
|
526
529
|
In React (or Svelte, or anything else) mount it into a ref and destroy it on unmount; it needs no framework runtime:
|
|
527
530
|
|
package/dist/design-controls.js
CHANGED
|
@@ -1341,7 +1341,9 @@ export function createDesignControls(container, options = {}) {
|
|
|
1341
1341
|
fill.setOptions(CELL_FILLS.map(([value, label]) => ({ value, label })));
|
|
1342
1342
|
const align = selectField("cell-align", "Cell text alignment", { empty: "Default", onChange: (value) => run(() => setTableCellStyle(editor, dynamic.tablePath, dynamic.cell, { align: value === "" ? null : value }), "Cell alignment changed.") });
|
|
1343
1343
|
align.setOptions(["left", "center", "right"].map((value) => ({ value, label: titleCase(value) })));
|
|
1344
|
-
|
|
1344
|
+
// RR-93: `bold` is a cell style field, so a number cell stays bold without rich runs and keeps its number format and alignment. Unchecking removes the field.
|
|
1345
|
+
const bold = checkField("cell-bold", "Bold cell text", { onChange: (checked) => run(() => setTableCellStyle(editor, dynamic.tablePath, dynamic.cell, { bold: checked ? true : null }), checked ? "Cell text is bold." : "Cell text is no longer bold.") });
|
|
1346
|
+
const cellBox = h("div", { class: "opf-dc-cell" }, cellLabel, columns.wrap, rows.wrap, join.wrap, h("div", { class: "opf-dc-actions" }, merge, split), fill.wrap, align.wrap, bold.wrap);
|
|
1345
1347
|
// FA-27: the table's text alternative, like a chart's. It belongs to the table, so a dataset-backed table has it too.
|
|
1346
1348
|
const alt = textField("table-alt", "Alt text", {
|
|
1347
1349
|
help: "What the table shows: its point and the key numbers, not \"a table\". Optional, because a screen reader reads a table cell by cell. Press Enter to apply.",
|
|
@@ -1354,7 +1356,7 @@ export function createDesignControls(container, options = {}) {
|
|
|
1354
1356
|
});
|
|
1355
1357
|
const styleControls = [headerStyle.wrap, banding.wrap, borders.wrap, resetStyle, cellBox];
|
|
1356
1358
|
body.append(summary, alt.wrap, decorative.wrap, ...styleControls);
|
|
1357
|
-
dynamic.table = { details, summary, alt, decorative, styleControls, headerStyle, banding, borders, cellBox, cellLabel, columns, rows, merge, split, fill, align, join };
|
|
1359
|
+
dynamic.table = { details, summary, alt, decorative, styleControls, headerStyle, banding, borders, cellBox, cellLabel, columns, rows, merge, split, fill, align, bold, join };
|
|
1358
1360
|
}
|
|
1359
1361
|
|
|
1360
1362
|
// --- sync -----------------------------------------------------------------------------------------
|
|
@@ -1445,6 +1447,7 @@ export function createDesignControls(container, options = {}) {
|
|
|
1445
1447
|
const fillValue = typeof state.style.fill === "string" ? state.style.fill : "";
|
|
1446
1448
|
tableUi.fill.set(CELL_FILLS.some(([value]) => value === fillValue) ? fillValue : fillValue ? "(custom)" : "");
|
|
1447
1449
|
tableUi.align.set(state.style.align ?? "");
|
|
1450
|
+
tableUi.bold.set(state.style.bold === true);
|
|
1448
1451
|
}
|
|
1449
1452
|
}
|
|
1450
1453
|
}
|
package/dist/table-options.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export declare function describeTableCell(table: unknown, cell: TableCellAddress
|
|
|
62
62
|
/** Merge `span.colSpan` x `span.rowSpan` cells from `cell`. `join` keeps the text of covered cells by joining it into the anchor; without it, covered text refuses with `merge-would-lose-content`. */
|
|
63
63
|
export declare function prepareTableMerge(presentation: unknown, tablePath: string, cell: TableCellAddress, span: { colSpan?: number; rowSpan?: number }, options?: { join?: boolean }): PreparedTableChange;
|
|
64
64
|
export declare function prepareTableSplit(presentation: unknown, tablePath: string, cell: TableCellAddress): PreparedTableChange;
|
|
65
|
-
/** Merge style fields into the cells' styles (null removes a field, `style: null` clears). */
|
|
65
|
+
/** Merge style fields into the cells' styles (null removes a field, `style: null` clears). Fields include `fill`, `color`, `align`, `verticalAlign`, `padding`, `borders` and `bold` (boolean; keeps a numeric cell's number format and alignment, which rich runs would drop). */
|
|
66
66
|
export declare function prepareTableCellStyle(presentation: unknown, tablePath: string, cells: TableCellAddress | TableCellAddress[], style: Record<string, unknown> | null): PreparedTableChange;
|
|
67
67
|
/** Apply `{ header, banding, borders }` (missing fields mean theme/false) or a named preset: sets the header fill, banded-row fill and borders of every cell and clears them elsewhere; `theme` removes a previous style. */
|
|
68
68
|
export declare function prepareTableStyle(presentation: unknown, tablePath: string, preset: keyof typeof TABLE_STYLE_PRESETS | Partial<TableStyle>): PreparedTableChange;
|
package/dist/table-options.js
CHANGED
|
@@ -256,14 +256,16 @@ export function prepareTableSplit(presentation, tablePath, cell) {
|
|
|
256
256
|
|
|
257
257
|
/**
|
|
258
258
|
* Compute the patch that changes the style of the cells. `style` fields merge into each cell's style
|
|
259
|
-
* (fill, color, align, verticalAlign, padding, borders); a `null` field removes it, and `style: null`
|
|
260
|
-
* clears the whole style.
|
|
259
|
+
* (fill, color, bold, align, verticalAlign, padding, borders); a `null` field removes it, and `style: null`
|
|
260
|
+
* clears the whole style. `bold` is a boolean (RR-93): it bolds the whole cell and, unlike rich runs, keeps a
|
|
261
|
+
* numeric column's number `format` and alignment. Covered (merged) positions are skipped. A cell left with no style or spans
|
|
261
262
|
* becomes a plain value again. Style is appearance only: values and spans are untouched.
|
|
262
263
|
*/
|
|
263
264
|
export function prepareTableCellStyle(presentation, tablePath, cells, style) {
|
|
264
265
|
const list = Array.isArray(cells) ? cells : [cells];
|
|
265
266
|
if (!list.length) throw fail("table-cell-not-found", "Choose at least one cell.", {});
|
|
266
267
|
if (style !== null && !isObject(style)) throw fail("invalid-table-style", "A cell style is an object, or null to clear it.", { style });
|
|
268
|
+
if (style && Object.hasOwn(style, "bold") && style.bold !== null && style.bold !== undefined && typeof style.bold !== "boolean") throw fail("invalid-table-style", "Cell bold is true or false (null removes it).", { bold: style.bold });
|
|
267
269
|
return transaction(presentation, tablePath, (table) => {
|
|
268
270
|
let skipped = 0;
|
|
269
271
|
for (const cell of list) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openpresentation/opf-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Embeddable local OPF editor primitives built on the deterministic renderer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -266,11 +266,11 @@
|
|
|
266
266
|
"@codemirror/state": "6.7.6",
|
|
267
267
|
"@codemirror/view": "6.43.14",
|
|
268
268
|
"@lezer/highlight": "1.2.5",
|
|
269
|
-
"@openpresentation/opf": "^0.
|
|
269
|
+
"@openpresentation/opf": "^0.22.1",
|
|
270
270
|
"jsonc-parser": "3.3.1"
|
|
271
271
|
},
|
|
272
272
|
"peerDependencies": {
|
|
273
|
-
"@openpresentation/opf-render": "^0.
|
|
273
|
+
"@openpresentation/opf-render": "^0.22.2"
|
|
274
274
|
},
|
|
275
275
|
"peerDependenciesMeta": {
|
|
276
276
|
"@openpresentation/opf-render": {
|
|
@@ -323,8 +323,8 @@
|
|
|
323
323
|
"@expo-google-fonts/roboto-mono": "0.4.2",
|
|
324
324
|
"@expo-google-fonts/stix-two-math": "0.4.0",
|
|
325
325
|
"@expo-google-fonts/tinos": "0.4.2",
|
|
326
|
-
"@openpresentation/opf-pptx": "^0.
|
|
327
|
-
"@openpresentation/opf-render": "^0.
|
|
326
|
+
"@openpresentation/opf-pptx": "^0.22.0",
|
|
327
|
+
"@openpresentation/opf-render": "^0.22.2",
|
|
328
328
|
"@resvg/resvg-js": "2.6.2",
|
|
329
329
|
"axe-core": "4.14.0",
|
|
330
330
|
"esbuild": "0.28.2",
|