pptx-vanilla-viewer 0.2.0 → 0.4.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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n, o, m, P, a, e, f, X, p, q, r, s, t, u, v, w, x, y, z, A, B, D, E, F, G, H, J, K, L, i, j, l, k, g, h } from './presentation-BfnrtJV1.js';
1
+ import { n, o, m, P, a, e, f, X, p, q, r, s, t, u, v, w, x, y, z, A, B, D, E, F, G, H, J, K, L, i, j, l, k, g, h, a0, ca } from './presentation-BfnrtJV1.js';
2
2
  export { a as PptxElement, P as PptxSlide } from './presentation-BfnrtJV1.js';
3
3
  import { ViewerTheme } from './theme/index.js';
4
4
  export { ViewerTheme, ViewerThemeColors, defaultCssVars, defaultRadius, defaultThemeColors, themeToCssVars, vermilionDarkTheme, vermilionLightTheme } from './theme/index.js';
@@ -1431,6 +1431,71 @@ interface CollaborationConfig {
1431
1431
  /** A neutral CSS map (framework `CSSProperties` are structurally compatible). */
1432
1432
  type CssStyleMap = Record<string, string | number>;
1433
1433
 
1434
+ /**
1435
+ * `animation-authoring` — pure, immutable helpers for the editor's element
1436
+ * animation authoring UI (the Animations ribbon tab / animation panel).
1437
+ *
1438
+ * Animation data lives on the SLIDE (`PptxSlide.animations`), keyed by
1439
+ * `elementId`, NOT on the element itself. The authoring UI reads and emits the
1440
+ * entire slide-level `animations` array. Every function here returns a new
1441
+ * `PptxElementAnimation[]` without mutating its input, so they're trivially
1442
+ * unit-testable and safe to drive editor undo/redo from.
1443
+ *
1444
+ * Two families coexist here, both used across the bindings:
1445
+ *
1446
+ * - **Granular field setters** (`setAnimationEntrance` / `setTrigger` /
1447
+ * `setDuration` / … plus `reorderAnimationUp` / `removeAnimation`): the
1448
+ * Angular authoring panel + React's `useAnimationHandlers` model. They
1449
+ * upsert a single field on the element's entry, creating the entry with
1450
+ * sensible defaults when absent and removing it when all three effect
1451
+ * buckets become empty.
1452
+ * - **Group preset apply/remove** (`applyAnimationPreset` /
1453
+ * `removeElementAnimation`): the Vue ribbon model, a coarser
1454
+ * "set one of entrance/emphasis/exit, keep the rest" upsert.
1455
+ *
1456
+ * The option *catalogs* here are intentionally **value-only** (preset id +
1457
+ * nothing else): the human label / icon / i18n key for each option is
1458
+ * framework-specific (React uses `react-icons` + label keys, Angular uses
1459
+ * Unicode arrow glyphs + plain labels), so each binding maps these ids to its
1460
+ * own display metadata.
1461
+ *
1462
+ * Pure: imports only `pptx-viewer-core` types; no framework, no DOM.
1463
+ *
1464
+ * @module render/animation-authoring
1465
+ */
1466
+
1467
+ /** One of the three animation buckets a preset can occupy on an element. */
1468
+ type AnimationGroup = 'entrance' | 'emphasis' | 'exit';
1469
+
1470
+ /**
1471
+ * Pure geometry helpers for the align / distribute editor operations.
1472
+ *
1473
+ * These functions operate over a list of slide elements (anything carrying the
1474
+ * `{ id, x, y, width, height }` bounding-box fields of {@link PptxElement}) and
1475
+ * return a `Map` keyed by element `id` describing the *new* position(s) for the
1476
+ * elements that need to move. Elements that already sit on the target edge (or
1477
+ * the two outer-most elements during distribution) are still included with
1478
+ * their unchanged coordinate so callers can apply the whole map uniformly — the
1479
+ * map only ever contains the axis that the operation touches.
1480
+ *
1481
+ * The helpers are deliberately framework-agnostic: no DOM, no Vue reactivity,
1482
+ * no side effects. The host wires them into the editor by feeding the current
1483
+ * selection in and applying the returned `Map` via its element-transform
1484
+ * operation (one batched history entry per call).
1485
+ */
1486
+ /** Edge / centre that {@link alignElements} can snap a selection to. */
1487
+ type AlignEdge = 'left' | 'centerH' | 'right' | 'top' | 'middle' | 'bottom';
1488
+
1489
+ /**
1490
+ * "Change Case" text mutation (PowerPoint's Aa dropdown: Sentence case, lower,
1491
+ * UPPER, Capitalize Each Word, tOGGLE cASE). Unlike `textCaps` (a purely
1492
+ * visual `text-transform`-style render hint), these modes rewrite the actual
1493
+ * characters, matching PowerPoint's own behaviour. Framework-agnostic; no
1494
+ * framework imports.
1495
+ */
1496
+
1497
+ type ChangeCaseMode = 'sentence' | 'lower' | 'upper' | 'capitalize' | 'toggle';
1498
+
1434
1499
  /**
1435
1500
  * collaboration-presence.ts: Pure, framework-agnostic logic for the real-time
1436
1501
  * collaboration subsystem (Yjs-backed presence + remote cursors).
@@ -1455,6 +1520,54 @@ type CssStyleMap = Record<string, string | number>;
1455
1520
 
1456
1521
  /** Connection lifecycle states for the Yjs WebSocket provider. */
1457
1522
  type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
1523
+
1524
+ /**
1525
+ * Pure helpers for the gradient picker editor control, shared by every binding.
1526
+ *
1527
+ * Readers extract current gradient values from a PptxElement (falling back to
1528
+ * sensible defaults), and patch-builders produce shallow-merge-ready
1529
+ * `Partial<PptxElement>` objects safe to pass to each binding's element-update
1530
+ * action.
1531
+ *
1532
+ * No framework imports; every type is concrete or `unknown` + narrowed.
1533
+ */
1534
+
1535
+ /** A single gradient stop, mirroring the ShapeStyle array item shape. */
1536
+ interface GradientStop {
1537
+ color: string;
1538
+ position: number;
1539
+ opacity?: number;
1540
+ }
1541
+ /** The editable gradient state surfaced to the component. */
1542
+ interface GradientState {
1543
+ type: 'linear' | 'radial';
1544
+ /** Angle in degrees (only meaningful for linear). */
1545
+ angle: number;
1546
+ stops: GradientStop[];
1547
+ }
1548
+ /** In-memory clipboard payload stored when an element is copied or cut. */
1549
+ interface ElementClipboardPayload {
1550
+ element: a;
1551
+ isTemplate: boolean;
1552
+ }
1553
+
1554
+ /**
1555
+ * shape-preset-catalog.ts: the Insert > Shape picker catalogue shared by every
1556
+ * binding's toolbar/inspector.
1557
+ *
1558
+ * Pure data: each entry carries the preset geometry `type` (OOXML `a:prstGeom`
1559
+ * value the editor can insert), an English fallback `label`, the shared-i18n
1560
+ * `i18nKey`, and a framework-neutral icon descriptor ({@link ShapePresetGlyph}
1561
+ * name + optional utility-class modifier for rotation/skew). Each binding maps
1562
+ * the glyph name onto its own icon component/SVG.
1563
+ *
1564
+ * Order matters: bindings surface the first 12 entries as the quick "top
1565
+ * shapes" row, so new presets should be appended, not inserted.
1566
+ *
1567
+ * @module render/shape-preset-catalog
1568
+ */
1569
+ /** Shape preset geometry types offered by the insert picker. */
1570
+ type ShapePresetType = 'rect' | 'roundRect' | 'ellipse' | 'cylinder' | 'rtArrow' | 'leftArrow' | 'upArrow' | 'downArrow' | 'triangle' | 'rtTriangle' | 'diamond' | 'parallelogram' | 'trapezoid' | 'pentagon' | 'hexagon' | 'octagon' | 'chevron' | 'star5' | 'star6' | 'star8' | 'plus' | 'heart' | 'cloud' | 'sun' | 'moon' | 'pie' | 'plaque' | 'teardrop' | 'line' | 'connector';
1458
1571
  interface AutosaveRecord {
1459
1572
  key: string;
1460
1573
  data: Uint8Array;
@@ -1506,29 +1619,6 @@ interface PrintSettings {
1506
1619
  customRangeTo: number;
1507
1620
  }
1508
1621
 
1509
- /**
1510
- * Minimal i18n for the vanilla binding.
1511
- *
1512
- * The other bindings delegate to their framework's i18n runtime (react-i18next,
1513
- * vue-i18n, ngx-translate) fed by the shared `pptx.*` dictionary. The vanilla
1514
- * binding has no framework, so this module provides the one missing piece: a
1515
- * `t(key, params)` lookup with `{{param}}` interpolation over the same shared
1516
- * English dictionary, plus per-locale overrides supplied by the host.
1517
- *
1518
- * Resolution order: host dictionary for the active locale, then the built-in
1519
- * English dictionary, then a humanised fallback derived from the key (shared
1520
- * `keyToLabel`), so a missing key never renders as a raw `pptx.*` string.
1521
- */
1522
- /** Translate a dotted `pptx.*` key with optional `{{param}}` interpolation. */
1523
- type Translator = (key: string, params?: Record<string, string | number>) => string;
1524
- /** Locale to flat `key: message` dictionary map supplied by the host. */
1525
- type TranslationMessages = Record<string, Record<string, string>>;
1526
- /**
1527
- * Build a {@link Translator} for a locale. `messages[locale]` (when provided)
1528
- * wins over the built-in English dictionary; English is always the fallback.
1529
- */
1530
- declare function createTranslator(locale?: string, messages?: TranslationMessages): Translator;
1531
-
1532
1622
  /**
1533
1623
  * A tiny framework-free reactive store: `get` / `set(patch)` / `subscribe`.
1534
1624
  *
@@ -1587,6 +1677,81 @@ interface ViewerState {
1587
1677
  * navigation for the life of the viewer instance (in-memory only).
1588
1678
  */
1589
1679
  notesExpanded: boolean;
1680
+ /** In-memory clipboard payload from the last copy/cut, or null. */
1681
+ clipboardPayload: ElementClipboardPayload | null;
1682
+ }
1683
+
1684
+ /**
1685
+ * Element-animation actions for the ribbon's Animations tab.
1686
+ *
1687
+ * Animation data lives on the SLIDE (`PptxSlide.animations`, keyed by
1688
+ * `elementId`), not on the element itself, matching how the presentation
1689
+ * playback state machine reads it (`buildClickGroups(slide.animations)` in
1690
+ * `animation/presentation-playback.ts`). Both actions target the currently
1691
+ * selected element and route through the shared `animation-authoring.ts`
1692
+ * "coarse group preset" model (`applyAnimationPreset` / `removeElementAnimation`),
1693
+ * the same one the Vue ribbon uses: applying a preset sets one of
1694
+ * entrance/emphasis/exit without touching the others; remove drops the whole
1695
+ * entry.
1696
+ */
1697
+ interface AnimationActions {
1698
+ addAnimation(group: AnimationGroup, preset: g): void;
1699
+ removeAnimation(): void;
1700
+ }
1701
+
1702
+ /**
1703
+ * Z-order, align, flip, and group/ungroup actions for the ribbon's
1704
+ * Home > Arrange group.
1705
+ *
1706
+ * Align/distribute: the vanilla editor's selection model is single-element
1707
+ * only (see `state/viewer-state.ts`), so `alignElements` reaches the
1708
+ * single-selection "align to slide" mode ({@link alignToCanvas}), matching
1709
+ * PowerPoint's own behaviour when nothing else is selected. Multi-selection
1710
+ * "align to selection bounding box" / distribute (needing >= 2 / >= 3
1711
+ * elements, see `editor-arrange-mutations.ts`) is unreachable until a
1712
+ * multi-select model lands; `canDistribute` is therefore always `false` today
1713
+ * (see `editing-chrome-sync.ts`), a documented limitation rather than a bug.
1714
+ *
1715
+ * Group: needs >= 2 selected elements to be meaningful, so it too is
1716
+ * unreachable under single selection; `groupSelected` is a deliberate no-op
1717
+ * kept only so the ribbon button (permanently disabled, with an explanatory
1718
+ * title) has something to call. Ungroup works today: it applies to whichever
1719
+ * single `group` element is selected.
1720
+ */
1721
+ interface ArrangeActions {
1722
+ bringForward(): void;
1723
+ sendBackward(): void;
1724
+ bringToFront(): void;
1725
+ sendToBack(): void;
1726
+ alignElements(edge: AlignEdge): void;
1727
+ flipHorizontal(): void;
1728
+ flipVertical(): void;
1729
+ groupSelected(): void;
1730
+ ungroupSelected(): void;
1731
+ }
1732
+
1733
+ /**
1734
+ * Slide-background actions for the ribbon's Design > Format Background panel.
1735
+ * Solid-colour fill only (matches the docked panel's scope: a single colour
1736
+ * input); clearing removes every background field so the slide falls back to
1737
+ * its layout/master background. Both mutations are history-integrated,
1738
+ * mirroring `editor-slide-actions.ts`.
1739
+ */
1740
+ interface SlideBackgroundActions {
1741
+ setSlideBackgroundColor(color: string): void;
1742
+ clearSlideBackground(): void;
1743
+ }
1744
+
1745
+ /**
1746
+ * Cut/copy/paste actions for the ribbon's Home > Clipboard group, backed by
1747
+ * the shared `element-clipboard.ts` codec. The in-memory clipboard payload
1748
+ * lives on `ViewerState.clipboardPayload` (not a module-level variable) so
1749
+ * the ribbon's selection sync can reactively enable/disable the Paste button.
1750
+ */
1751
+ interface ClipboardActions {
1752
+ copy(): void;
1753
+ cut(): void;
1754
+ paste(): void;
1590
1755
  }
1591
1756
 
1592
1757
  /**
@@ -1599,29 +1764,96 @@ interface ViewerState {
1599
1764
  * side effects needed to turn a chosen image file into a data-URL image
1600
1765
  * element; it too returns a centred, ready-to-insert element.
1601
1766
  */
1602
- /** The shape/text/table element kinds the insert menu can create directly. */
1603
- type InsertKind = 'text' | 'rect' | 'ellipse' | 'line' | 'table';
1767
+ /** The element kinds the Insert ribbon tab can create directly. */
1768
+ type InsertKind = 'text' | 'table' | 'shape';
1604
1769
 
1605
- /** The selection-derived state the toolbar reflects (enable/disable + values). */
1606
- interface FormatSelectionState {
1607
- hasSelection: boolean;
1608
- canText: boolean;
1609
- canShape: boolean;
1610
- bold: boolean;
1611
- italic: boolean;
1612
- underline: boolean;
1613
- fontSize: number;
1614
- textColor: string | undefined;
1615
- highlightColor: string | undefined;
1616
- fillColor: string | undefined;
1617
- strokeColor: string | undefined;
1770
+ /**
1771
+ * Element-type-aware inspector actions: text vertical-align/wrap/autofit,
1772
+ * gradient fill + fill/stroke opacity, image brightness/contrast/saturation +
1773
+ * crop, and table-level header-row/banded-rows/cell-padding. Every method is a
1774
+ * thin `applyToSelected` wrapper around pure builders from `pptx-viewer-shared`
1775
+ * (or the local `patchShapeStyle`), mirroring `editor-text-actions.ts`.
1776
+ *
1777
+ * These extend the base position/size/rotation + flat fill/stroke inspector
1778
+ * that `editor-edit-ops.ts` already exposes; see `ui/inspector/` for the
1779
+ * per-element-type panels that call these.
1780
+ */
1781
+ interface InspectorActions {
1782
+ setTextVerticalAlign(vAlign: NonNullable<a0['vAlign']>): void;
1783
+ setTextWrap(wrap: NonNullable<a0['textWrap']>): void;
1784
+ setAutoFitMode(mode: NonNullable<a0['autoFitMode']>): void;
1785
+ setFillOpacity(opacity: number): void;
1786
+ setStrokeOpacity(opacity: number): void;
1787
+ setGradientFill(state: GradientState): void;
1788
+ addGradientStop(color: string, position: number): void;
1789
+ removeGradientStop(index: number): void;
1790
+ updateGradientStop(index: number, changes: Partial<GradientState['stops'][number]>): void;
1791
+ setImageBrightness(value: number): void;
1792
+ setImageContrast(value: number): void;
1793
+ setImageSaturation(value: number): void;
1794
+ setImageCrop(edge: 'left' | 'top' | 'right' | 'bottom', value: number): void;
1795
+ setTableHeaderRow(enabled: boolean): void;
1796
+ setTableBandedRows(enabled: boolean): void;
1797
+ setTableCellPadding(padding: number): void;
1618
1798
  }
1619
- interface FormatToolbar {
1620
- el: HTMLElement;
1621
- /** Reflect the current selection (enable/disable controls + seed values). */
1622
- update(state: FormatSelectionState): void;
1623
- /** Show/hide the whole row (editing mode on/off). */
1624
- setEditable(editable: boolean): void;
1799
+
1800
+ /**
1801
+ * New/duplicate/delete-slide actions for the ribbon's Home > Slides group,
1802
+ * backed by the shared `slide-operations.ts` factory. Every mutation is
1803
+ * history-integrated (matches the element-level actions in `editor-edit-ops`)
1804
+ * and renumbers `slideNumber` across the whole deck so it always matches the
1805
+ * array index (mirrors the Vue `useSlideOperations` contract).
1806
+ */
1807
+ interface SlideActions {
1808
+ addSlide(): void;
1809
+ duplicateSlide(): void;
1810
+ deleteSlide(): void;
1811
+ }
1812
+
1813
+ /**
1814
+ * Character + paragraph formatting actions for the ribbon's Home > Font and
1815
+ * Home > Paragraph groups. Every method is a thin `applyToSelected` wrapper
1816
+ * around the pure builders in `editor-format-mutations.ts` /
1817
+ * `editor-paragraph-mutations.ts`; this file owns none of the mutation logic
1818
+ * itself, only the selection/history wiring shared by the whole action set.
1819
+ */
1820
+ interface TextActions {
1821
+ toggleBold(): void;
1822
+ toggleItalic(): void;
1823
+ toggleUnderline(): void;
1824
+ toggleStrikethrough(): void;
1825
+ toggleTextShadow(): void;
1826
+ changeFontSize(delta: number): void;
1827
+ setFontSize(size: number): void;
1828
+ setFontFamily(family: string): void;
1829
+ setTextColor(color: string): void;
1830
+ setHighlightColor(color: string): void;
1831
+ setCharacterSpacing(value: number): void;
1832
+ changeCase(mode: ChangeCaseMode): void;
1833
+ clearFormatting(): void;
1834
+ toggleBulletList(): void;
1835
+ toggleNumberedList(): void;
1836
+ increaseIndent(): void;
1837
+ decreaseIndent(): void;
1838
+ setTextAlign(align: a0['align']): void;
1839
+ setLineSpacing(value: number): void;
1840
+ }
1841
+
1842
+ /**
1843
+ * Slide-transition actions for the ribbon's Transitions tab. Playback already
1844
+ * reads `PptxSlide.transition` (see `animation/presentation-playback.ts`), so
1845
+ * this only needs to write that same field, history-integrated like every
1846
+ * other ribbon mutation.
1847
+ *
1848
+ * `applyTransition` covers both the preset gallery buttons and the duration
1849
+ * input (the tab re-applies the currently-selected preset whenever the
1850
+ * duration changes), plus the "Apply to All Slides" checkbox: when
1851
+ * `applyToAll` is true every slide gets the same fresh `{ type, durationMs }`
1852
+ * transition; otherwise only the current slide is patched, preserving any
1853
+ * advanced fields (direction, sound, ...) it already carried.
1854
+ */
1855
+ interface TransitionActions {
1856
+ applyTransition(type: k, durationMs: number, applyToAll: boolean): void;
1625
1857
  }
1626
1858
 
1627
1859
  /** A geometry patch from the inspector (all fields optional). */
@@ -1633,35 +1865,80 @@ interface GeometryPatch {
1633
1865
  rotation?: number;
1634
1866
  }
1635
1867
  /**
1636
- * The formatting / insert / arrange actions exposed to the editing chrome
1637
- * (format toolbar, inspector, insert menu). Every mutating action is
1638
- * history-integrated (push -> mutate -> commit) via the shared {@link EditorOps}.
1868
+ * The full set of formatting / insert / arrange / clipboard / slide actions
1869
+ * exposed to the editing chrome (ribbon, inspector). Composed from the
1870
+ * focused per-concern action files (`editor-text-actions.ts`,
1871
+ * `editor-arrange-actions.ts`, `editor-clipboard-actions.ts`,
1872
+ * `editor-slide-actions.ts`) plus the shape/geometry/insert actions owned
1873
+ * directly here. Every mutating action is history-integrated (push -> mutate
1874
+ * -> commit) via the shared {@link EditorOps}.
1639
1875
  */
1640
- interface EditActions {
1641
- toggleBold(): void;
1642
- toggleItalic(): void;
1643
- toggleUnderline(): void;
1644
- changeFontSize(delta: number): void;
1645
- setFontSize(size: number): void;
1646
- setTextColor(color: string): void;
1647
- setHighlightColor(color: string): void;
1876
+ interface EditActions extends TextActions, ArrangeActions, ClipboardActions, SlideActions, SlideBackgroundActions, TransitionActions, AnimationActions, InspectorActions {
1648
1877
  setShapeFill(color: string): void;
1649
1878
  setShapeStroke(color: string): void;
1650
1879
  setShapeStrokeWidth(width: number): void;
1651
1880
  /** Commit an inspector geometry edit (X/Y/W/H/rotation). */
1652
1881
  setGeometry(patch: GeometryPatch): void;
1653
- insert(kind: InsertKind): void;
1882
+ insert(kind: InsertKind, shapeType?: ShapePresetType): void;
1654
1883
  insertImage(): Promise<void>;
1655
- bringForward(): void;
1656
- sendBackward(): void;
1657
- bringToFront(): void;
1658
- sendToBack(): void;
1884
+ insertMedia(): Promise<void>;
1885
+ insertChart(chartType: l): void;
1886
+ insertSmartArt(layout: ca, defaultItems: string[]): void;
1887
+ insertEquation(omml: Record<string, unknown>): void;
1888
+ insertActionButton(shapeType: string): void;
1889
+ insertField(fieldType: string, value?: string): void;
1890
+ duplicateSelected(): void;
1891
+ deleteSelected(): void;
1892
+ }
1893
+
1894
+ /**
1895
+ * Find & Replace actions for the ribbon's Home > Editing group, backed by the
1896
+ * shared `find-replace.ts` helpers. A lean, docked-panel implementation:
1897
+ * `search` reports a match count for the query, `replaceCurrent` replaces the
1898
+ * first match, and `replaceAll` replaces every match; there is no in-canvas
1899
+ * match highlighting or "next/previous match" cursor (that needs per-match
1900
+ * selection/scroll wiring into the renderer, out of scope for this wave).
1901
+ * Every replace is history-integrated like every other editor action.
1902
+ */
1903
+ interface FindReplaceActions {
1904
+ /** Count occurrences of `query` across all slides (does not mutate). */
1905
+ search(query: string, matchCase: boolean): number;
1906
+ /** Replace the first match of `query`; returns the number replaced (0 or 1). */
1907
+ replaceCurrent(query: string, replacement: string, matchCase: boolean): number;
1908
+ /** Replace every match of `query`; returns the number replaced. */
1909
+ replaceAll(query: string, replacement: string, matchCase: boolean): number;
1659
1910
  }
1660
1911
 
1661
- /** Selection-derived state the inspector reflects. */
1912
+ /**
1913
+ * Minimal i18n for the vanilla binding.
1914
+ *
1915
+ * The other bindings delegate to their framework's i18n runtime (react-i18next,
1916
+ * vue-i18n, ngx-translate) fed by the shared `pptx.*` dictionary. The vanilla
1917
+ * binding has no framework, so this module provides the one missing piece: a
1918
+ * `t(key, params)` lookup with `{{param}}` interpolation over the same shared
1919
+ * English dictionary, plus per-locale overrides supplied by the host.
1920
+ *
1921
+ * Resolution order: host dictionary for the active locale, then the built-in
1922
+ * English dictionary, then a humanised fallback derived from the key (shared
1923
+ * `keyToLabel`), so a missing key never renders as a raw `pptx.*` string.
1924
+ */
1925
+ /** Translate a dotted `pptx.*` key with optional `{{param}}` interpolation. */
1926
+ type Translator = (key: string, params?: Record<string, string | number>) => string;
1927
+ /** Locale to flat `key: message` dictionary map supplied by the host. */
1928
+ type TranslationMessages = Record<string, Record<string, string>>;
1929
+ /**
1930
+ * Build a {@link Translator} for a locale. `messages[locale]` (when provided)
1931
+ * wins over the built-in English dictionary; English is always the fallback.
1932
+ */
1933
+ declare function createTranslator(locale?: string, messages?: TranslationMessages): Translator;
1934
+
1935
+ /** Selection-derived state the inspector reflects, computed by `buildInspectorState`. */
1662
1936
  interface InspectorState {
1663
1937
  hasSelection: boolean;
1664
1938
  canShape: boolean;
1939
+ canText: boolean;
1940
+ isImage: boolean;
1941
+ isTable: boolean;
1665
1942
  x: number;
1666
1943
  y: number;
1667
1944
  width: number;
@@ -1670,6 +1947,23 @@ interface InspectorState {
1670
1947
  fillColor: string | undefined;
1671
1948
  strokeColor: string | undefined;
1672
1949
  strokeWidth: number;
1950
+ fillOpacity: number;
1951
+ strokeOpacity: number;
1952
+ gradientEnabled: boolean;
1953
+ gradient: GradientState;
1954
+ vAlign: 'top' | 'middle' | 'bottom';
1955
+ textWrap: 'square' | 'none';
1956
+ autoFitMode: 'shrink' | 'normal' | 'none';
1957
+ imageBrightness: number;
1958
+ imageContrast: number;
1959
+ imageSaturation: number;
1960
+ cropLeft: number;
1961
+ cropTop: number;
1962
+ cropRight: number;
1963
+ cropBottom: number;
1964
+ tableHeaderRow: boolean;
1965
+ tableBandedRows: boolean;
1966
+ tableCellPadding: number;
1673
1967
  }
1674
1968
  interface Inspector {
1675
1969
  el: HTMLElement;
@@ -1694,52 +1988,52 @@ interface NotesPanel {
1694
1988
  setExpanded(expanded: boolean): void;
1695
1989
  }
1696
1990
 
1697
- interface ThumbnailRail {
1698
- el: HTMLElement;
1699
- /** Rebuild the rail for a new slide list (uses `renderStage` per slide). */
1700
- render(slides: P[], canvasSize: CanvasSize, renderStage: (slide: P, scale: number) => HTMLElement): void;
1701
- /** Highlight the active slide and scroll it into view. */
1702
- setActive(index: number): void;
1703
- /** Show or hide the rail. */
1704
- setVisible(visible: boolean): void;
1705
- }
1706
-
1707
- interface ToolbarUpdate {
1708
- /** Zero-based current slide index. */
1991
+ /** Nav-row state (prev/next/counter/zoom label). */
1992
+ interface RibbonNavState {
1709
1993
  current: number;
1710
- /** Total slide count. */
1711
1994
  total: number;
1712
- /** Effective zoom percentage (100 = 1:1). */
1713
1995
  zoomPercent: number;
1714
1996
  }
1715
- /** Editing-cluster state (Save / Undo / Redo buttons). */
1716
- interface ToolbarEditState {
1717
- /** Shows/hides the whole editing cluster. */
1997
+ /** Primary-row + tab-bar visibility state. */
1998
+ interface RibbonEditState {
1718
1999
  editable: boolean;
1719
2000
  canUndo: boolean;
1720
2001
  canRedo: boolean;
1721
2002
  }
1722
- interface Toolbar {
2003
+ /** Selection-derived state the Home tab's Font/Paragraph/Arrange groups reflect. */
2004
+ interface RibbonSelectionState {
2005
+ hasClipboard: boolean;
2006
+ slideCount: number;
2007
+ }
2008
+
2009
+ interface Ribbon {
1723
2010
  el: HTMLElement;
1724
- update(state: ToolbarUpdate): void;
1725
- setEditState(state: ToolbarEditState): void;
1726
- /** Reflect the notes panel's expanded/collapsed state on the Notes button. */
2011
+ update(state: RibbonNavState): void;
2012
+ setEditState(state: RibbonEditState): void;
1727
2013
  setNotesExpanded(expanded: boolean): void;
1728
- /**
1729
- * Show the autosave status pill. `label` is the (already localized) text;
1730
- * `kind` drives the styling hook (`is-saving` / `is-error`). An empty label
1731
- * hides the pill.
1732
- */
1733
2014
  setAutosaveStatus(label: string, kind: 'idle' | 'saving' | 'saved' | 'error'): void;
2015
+ /** Show/hide the whole editing surface (Home/Insert tab content + find/replace). */
2016
+ setEditable(editable: boolean): void;
2017
+ /** Reflect the current selection across the Home tab's Font/Paragraph/Arrange groups. */
2018
+ updateSelection(selectedElement: a | undefined, extra: RibbonSelectionState): void;
2019
+ }
2020
+
2021
+ interface ThumbnailRail {
2022
+ el: HTMLElement;
2023
+ /** Rebuild the rail for a new slide list (uses `renderStage` per slide). */
2024
+ render(slides: P[], canvasSize: CanvasSize, renderStage: (slide: P, scale: number) => HTMLElement): void;
2025
+ /** Highlight the active slide and scroll it into view. */
2026
+ setActive(index: number): void;
2027
+ /** Show or hide the rail. */
2028
+ setVisible(visible: boolean): void;
1734
2029
  }
1735
2030
 
1736
2031
  /** The viewer's static DOM skeleton plus the mutable overlay controls. */
1737
2032
  interface ViewerChrome {
1738
2033
  /** `.pptxv` root (focusable; keyboard navigation attaches here). */
1739
2034
  root: HTMLElement;
1740
- toolbar: Toolbar | null;
1741
- /** Editing format toolbar (bold/fill/insert/z-order); null when disabled. */
1742
- formatToolbar: FormatToolbar | null;
2035
+ /** The tabbed ribbon (primary row, nav row, tab bar + File/Home/Insert/View content); null when disabled. */
2036
+ ribbon: Ribbon | null;
1743
2037
  /** Property inspector panel; null when disabled. */
1744
2038
  inspector: Inspector | null;
1745
2039
  thumbnails: ThumbnailRail | null;
@@ -1786,6 +2080,8 @@ interface EditorController {
1786
2080
  getSelectedElementId(): string | null;
1787
2081
  /** The formatting / insert / arrange actions for the editing chrome. */
1788
2082
  getEditActions(): EditActions;
2083
+ /** The Find & Replace actions for the ribbon's docked panel. */
2084
+ getFindReplaceActions(): FindReplaceActions;
1789
2085
  /** Commit the speaker-notes textarea's plain text onto the current slide. */
1790
2086
  commitNotes(notes: string): void;
1791
2087
  save(): Promise<Uint8Array>;
@@ -2367,6 +2663,7 @@ interface ChromeHost {
2367
2663
  editor: {
2368
2664
  commitNotes(notes: string): void;
2369
2665
  getEditActions(): EditActions;
2666
+ getFindReplaceActions(): FindReplaceActions;
2370
2667
  };
2371
2668
  prev(): void;
2372
2669
  next(): void;
@@ -2381,6 +2678,12 @@ interface ChromeHost {
2381
2678
  getSlideCount(): number;
2382
2679
  enterPresentation(): Promise<void>;
2383
2680
  exitPresentation(): Promise<void>;
2681
+ exportSlidePng(): Promise<void>;
2682
+ exportPdf(): Promise<void>;
2683
+ exportGif(): Promise<void>;
2684
+ exportVideo(): Promise<void>;
2685
+ print(): Promise<boolean>;
2686
+ setTheme(theme: ViewerTheme | undefined): void;
2384
2687
  }
2385
2688
 
2386
2689
  /** The export slice of the public viewer API (see `PptxViewerInstance`). */