import { ComponentOptionsMixin } from 'vue'; import { ComponentProvideOptions } from 'vue'; import { ComputedRef } from 'vue'; import { CSSProperties as CSSProperties_2 } from 'vue'; import { DefineComponent } from 'vue'; import { Doc } from 'yjs'; import { InjectionKey } from 'vue'; import { MaybeRefOrGetter } from 'vue'; import { PublicProps } from 'vue'; import { Ref } from 'vue'; import { ShallowRef } from 'vue'; declare const __VLS_export: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {} & { done: () => any; }, string, PublicProps, Readonly<__VLS_Props> & Readonly<{ onDone?: (() => any) | undefined; }>, { scale: number; }, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>; declare const __VLS_export_2: DefineComponent<__VLS_Props_2, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props_2> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>; declare const __VLS_export_3: DefineComponent<__VLS_Props_3, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props_3> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>; /** * PresentationTransitionOverlay - animates a slide change in presentation mode. * * It stacks two {@link SlideStage} layers, both scaled-to-fit identically to the * underlying presentation frame: * - the **outgoing** (old) slide as a snapshot layer, and * - the **incoming** (new) slide. * * The active slide's {@link PptxSlideTransition} is mapped to CSS `animation` * shorthands (via {@link resolveSlideTransition}); each layer's `z-index` is set * from `outgoingOnTop`. When the configured duration elapses the overlay emits * `done`, at which point the host should drop the overlay and leave the static * incoming slide rendered by its main stage. * * `PresentationMode` is expected to mount this **only while a transition is * playing** (between the outgoing and incoming slides), render nothing of its * own animated stage during that window, and remove it on `@done`. */ declare type __VLS_Props = { /** The outgoing (previous) slide rendered in the exit layer. */ outgoingSlide: PptxSlide | undefined; /** The incoming (new) slide rendered in the entrance layer. */ incomingSlide: PptxSlide | undefined; /** Slide surface dimensions (px). */ canvasSize: CanvasSize; /** Resolved media data URLs, threaded to each {@link SlideStage}. */ mediaDataUrls: Map; /** Fit-to-viewport scale (same value the host applies to its main stage). */ scale?: number; /** The transition definition from the incoming slide. */ transition: PptxSlideTransition | undefined; }; /** * The two morph-only layers `PresentationTransitionOverlay.vue` paints ABOVE * its outgoing/incoming pair, split out to keep that file under the * project's per-file LOC budget: * * - the **lifted** layer: arriving shapes a ghost above them would * otherwise hide for the whole morph, painted here so they dissolve in * where a viewer can see them (issue #146). Their copy on the incoming * layer is held invisible by the plan, so nothing composites twice. * - the **crossfade groups**: pairs the overlay paints BOTH halves of, each * as one isolated group so the halves are SUMMED rather than stacked * (issue #161). */ declare type __VLS_Props_2 = { liftedSlide: PptxSlide | undefined; liftedLayerStyle: CSSProperties_2; crossfadeGroups: readonly MorphCrossfadeGroupView[]; canvasSize: CanvasSize; mediaDataUrls: Map; scale: number; }; /** * FragmentedTransitionLayer - renders one `FragmentedLayer` (from * `getFragmentedTransitionDescriptor` in `pptx-viewer-shared`) as N clipped * copies of `SlideStage` - the Vue mapping of the seven multi-fragment * cinematic transitions (`vortex`, `honeycomb`, `glitter`, `shred`, * `fracture`, `curtains`, `airplane`; see `slide-transition-fragments.ts` in * `pptx-viewer-shared` for the COM measurement and the pure decision * function this maps). * * Every fragment is `position:absolute` + `clip-path` + a shared * `@keyframes` animation (already folded into the injected * `SLIDE_TRANSITION_KEYFRAMES_CSS` aggregate) parameterised by CSS custom * properties, so the whole set stays transform/opacity-only and * GPU-composited with no per-frame JS. * * Mounted by `PresentationTransitionOverlay.vue` INSIDE its existing * `data-pptx-transition-layer` wrapper, in place of a single `SlideStage`, * so the outer wrapper's z-index/`data-pptx-transition-fragments` marker are * unaffected by this split. */ declare type __VLS_Props_3 = { layer: FragmentedLayer; slide: PptxSlide | undefined; canvasSize: CanvasSize; mediaDataUrls: Map; scale: number; layerName: 'outgoing' | 'incoming'; }; declare interface AccessibilityCheckOptions { /** Minimum WCAG contrast ratio (default 4.5 for AA normal text). */ minContrastRatio?: number; /** Skip contrast checks (useful when background can't be resolved). */ skipContrast?: boolean; /** Skip blank slide checks. */ skipBlankSlide?: boolean; } declare interface AccessibilityIssue { type: AccessibilityIssueType; severity: AccessibilityIssueSeverity; slideIndex: number; elementId?: string; message: string; suggestion: string; } declare type AccessibilityIssueSeverity = 'error' | 'warning' | 'tip'; declare type AccessibilityIssueType = 'missingAltText' | 'missingSlideTitle' | 'lowContrast' | 'complexTable' | 'duplicateTitle' | 'blankSlide'; /** * Polar-style adjustment handle (`a:ahPolar`) on a custom geometry. * * Drives a guide via radial distance and angle rather than XY coordinates. * * @example * ```ts * const handle: AdjustHandlePolar = { * gdRefR: "adj1", * gdRefAng: "adj2", * posX: "wd2", * posY: "hd2", * }; * // => satisfies AdjustHandlePolar * ``` */ declare interface AdjustHandlePolar { /** Guide reference for the radial distance (`@_gdRefR`). */ gdRefR?: string; /** Guide reference for the angle (`@_gdRefAng`). */ gdRefAng?: string; /** Minimum radial value (`@_minR`). */ minR?: string; /** Maximum radial value (`@_maxR`). */ maxR?: string; /** Minimum angle (`@_minAng`). */ minAng?: string; /** Maximum angle (`@_maxAng`). */ maxAng?: string; /** Handle position X from `a:pos/@_x`. */ posX?: string; /** Handle position Y from `a:pos/@_y`. */ posY?: string; } /** * XY-style adjustment handle (`a:ahXY`) on a custom geometry. * * Allows interactive editing of one or two guide values constrained to a * rectangular range. Coordinates are formula references (e.g. `"adj1"`, * `"w/2"`, `"0"`) preserved verbatim so they can re-emit unchanged. * * @example * ```ts * const handle: AdjustHandleXY = { * gdRefX: "adj1", * minX: "0", * maxX: "w", * posX: "adj1", * posY: "h/2", * }; * // => satisfies AdjustHandleXY * ``` */ declare interface AdjustHandleXY { /** Guide reference for the X axis (`@_gdRefX`). */ gdRefX?: string; /** Guide reference for the Y axis (`@_gdRefY`). */ gdRefY?: string; /** Minimum X value, as a formula reference (`@_minX`). */ minX?: string; /** Maximum X value (`@_maxX`). */ maxX?: string; /** Minimum Y value (`@_minY`). */ minY?: string; /** Maximum Y value (`@_maxY`). */ maxY?: string; /** Handle position X (formula or literal) from `a:pos/@_x`. */ posX?: string; /** Handle position Y from `a:pos/@_y`. */ posY?: string; } /** * Pure geometry helpers for the align / distribute editor operations. * * These functions operate over a list of slide elements (anything carrying the * `{ id, x, y, width, height }` bounding-box fields of {@link PptxElement}) and * return a `Map` keyed by element `id` describing the *new* position(s) for the * elements that need to move. Elements that already sit on the target edge (or * the two outer-most elements during distribution) are still included with * their unchanged coordinate so callers can apply the whole map uniformly; the * map only ever contains the axis that the operation touches. * * The reference box the selection is aligned against is either the union of * the selected boxes (PowerPoint's "Align Selected Objects") or the slide * itself ("Align to Slide"). PowerPoint defaults to the slide whenever a * single object is selected, which is why a one-element selection is not a * no-op once a `slideSize` is supplied: Align Center on a lone title is one * of the commonest arrange gestures there is. * * The helpers are deliberately framework-agnostic: no DOM, no Vue reactivity, * no side effects. The host wires them into the editor by feeding the current * selection in and applying the returned `Map` via its element-transform * operation (one batched history entry per call). */ /** Edge / centre that {@link alignElements} can snap a selection to. */ declare type AlignEdge = 'left' | 'centerH' | 'right' | 'top' | 'middle' | 'bottom'; /** * The bucket a ribbon gallery click targets. Widens the three preset buckets * with `motionPath` so a binding's single "apply animation" callback can carry * a motion-path preset id too, instead of every binding growing a second * callback threaded through the same six components. */ declare type AnimationApplyGroup = 'entrance' | 'emphasis' | 'exit' | 'motionPath'; /** A single click-triggered group of animations that play as one step. */ export declare interface AnimationClickGroup { /** Animations belonging to this group, in document order. */ animations: PptxElementAnimation[]; } /** * Structured representation of a single OOXML animation condition * from `p:cond` elements inside `p:stCondLst` or `p:endCondLst`. * * Conditions control when an animation starts or ends, and can reference * events, time delays, and target time node IDs. * * @example * ```ts * const cond: AnimationCondition = { * event: "onClick", * delay: 0, * targetShapeId: "shape_5", * }; * ``` */ declare interface AnimationCondition { /** Event that triggers the condition. */ event?: AnimationConditionEvent; /** * The media element/bookmark this condition fires for, when * {@link event} is `onMediaBookmark`. See {@link PptxMediaBookmarkTarget}. */ bookmarkTarget?: PptxMediaBookmarkTarget; /** Delay in milliseconds (from `@_delay`). "indefinite" is represented as -1. */ delay?: number; /** Target time node ID reference (from `@_tn`). */ targetTimeNodeId?: number; /** Target shape ID from `p:tgtEl/p:spTgt/@spid`. */ targetShapeId?: string; /** Whether the condition targets a slide (from `p:tgtEl/p:sldTgt`). */ targetSlide?: boolean; /** Full target choice, including `p:sndTgt` and `p:inkTgt`. */ target?: PptxAnimationTarget; } /** * Event types for animation conditions from `p:cond/@evt`. * * These map directly to OOXML condition event attribute values * (ISO/IEC 29500-1 S19.5.28 CT_TLTimeCondition). */ declare type AnimationConditionEvent = 'onBegin' | 'onEnd' | 'begin' | 'end' | 'onClick' | 'onMouseOver' | 'onMouseOut' | 'onNext' | 'onPrev' | 'onStopAudio' | 'onDblClick' | 'onMediaBookmark'; declare interface AnimationInput { preset: PptxAnimationPreset; trigger?: PptxAnimationTrigger; duration?: number; delay?: number; } export declare interface AnnotationPoint { x: number; y: number; } export declare interface AnnotationStroke { id: string; points: AnnotationPoint[]; color: string; width: number; opacity: number; } /** * Autosave status, surfaced for status-pill rendering. * * - `idle` : nothing has been saved yet (or no edits since mount). * - `disabled` : autosave is inactive because requirements are not met. * - `saving` : an `onSave` invocation is currently in flight. * - `saved` : the most recent save succeeded. * - `error` : the most recent save threw. */ export declare type AutosaveStatus = 'idle' | 'disabled' | 'saving' | 'saved' | 'error'; /** * Timer-injection seam so the debounce window is testable with * `vi.useFakeTimers()`. Defaults to the global `setTimeout` / * `clearTimeout`; tests can leave them unset (fake timers patch the * globals) or override explicitly. */ export declare interface AutosaveTimerApi { setTimer: (handler: () => void, timeoutMs: number) => number; clearTimer: (id: number) => void; } /** * Structural interface for the lazily-imported Yjs awareness surface. Every * binding's live `y-protocols/awareness` `Awareness` instance satisfies this. */ declare interface AwarenessLike { clientID?: number; setLocalStateField: (field: string, value: unknown) => void; getStates: () => Map>; on: (event: string, cb: () => void) => void; off?: (event: string, cb: () => void) => void; } declare type BackgroundInput = { type: 'solid'; color: string; } | { type: 'gradient'; /** * Slide backgrounds are stored as a ready-made CSS gradient string * (`PptxSlide.backgroundGradient`), so this is a CSS * `linear-gradient()` angle: degrees clockwise from "to top" * (`90` = left to right, `180` = top to bottom). Defaults to `180`. */ angle?: number; stops: Array<{ color: string; position: number; }>; } | { type: 'image'; source: string; }; /** * Every action card the File-tab backstage can show, keyed by the operation it * triggers rather than by its wording. * * The five bindings used to hardcode a title and a body string each, which made * the whole backstage untranslatable and let the copy drift: the same card * carried four different descriptions depending on which binding you opened it * in. Both halves now live here as a dictionary key plus an English fallback, * so a wording change lands everywhere at once and a translator only has to * translate it once. */ declare type BackstageCardId = 'protect' | 'inspect' | 'embedFonts' | 'signatures' | 'versionHistory' | 'saveAsPptx' | 'saveAsPpsx' | 'saveAsPptm' | 'saveAsPpt' | 'pdf' | 'png' | 'video' | 'gif' | 'json' | 'copyImage' | 'print' | 'share'; declare type BackstagePage = 'home' | 'new' | 'open' | 'info' | 'save' | 'saveAs' | 'print' | 'share' | 'export' | 'close' | 'account' | 'options'; declare interface BehaviorBase { /** Lower-cased `p:attrNameLst` entries, in document order. */ attrNames: string[]; /** `p:cBhvr/@additive` (`base`, `sum`, `repl`, `mult`, `none`). */ additive?: string; timing: PptxAnimationBehaviorTiming; } /** * 3-D effect properties, text warp (WordArt) presets, and scene/shape bevel * definitions parsed from OOXML `a:sp3d`, `a:scene3d`, and `a:bodyPr/a:prstTxWarp`. * * @module pptx-types/three-d */ /** * Bevel preset type tokens from OOXML `a:bevelT/@prst` / `a:bevelB/@prst`. * * @example * ```ts * const bevel: BevelPresetType = "circle"; * // => "circle" — one of: "circle" | "relaxedInset" | "cross" | "coolSlant" | "angle" | … * ``` */ declare type BevelPresetType = 'circle' | 'relaxedInset' | 'cross' | 'coolSlant' | 'angle' | 'softRound' | 'convex' | 'slope' | 'divot' | 'riblet' | 'hardEdge' | 'artDeco' | 'none'; /** Bounding box passed to every layout function. */ declare interface BoundingBox { width: number; height: number; } /** * Splits an ordered animation list into click groups. The first animation * always begins a group even if it isn't explicitly `onClick` (PowerPoint shows * the first build on the first advance). Subsequent `withPrevious` / * `afterPrevious` animations attach to the group in progress. */ export declare function buildClickGroups(animations: readonly PptxElementAnimation[]): AnimationClickGroup[]; /** * Structured bullet metadata attached to the first {@link TextSegment} * of each paragraph. * * Describes how the paragraph bullet should render: character bullets * (`char`), auto-numbered lists (`autoNumType`), or picture bullets * (`imageRelId` / `imageDataUrl`). Set `none: true` when `a:buNone` * explicitly suppresses the bullet. * * @example * ```ts * // Simple character bullet: * const bullet: BulletInfo = { char: "•", color: "#333333" }; * * // Auto-numbered list starting at 1: * const numbered: BulletInfo = { * autoNumType: "arabicPeriod", * autoNumStartAt: 1, * }; * // => { char: "•", color: "#333333" } and { autoNumType: "arabicPeriod", autoNumStartAt: 1 } * ``` */ declare interface BulletInfo { /** Bullet character (e.g. "•", "-", "»") from `a:buChar`. */ char?: string; /** Auto-numbering type (e.g. "arabicPeriod", "romanUcPeriod") from `a:buAutoNum`. */ autoNumType?: string; /** Auto-numbering start value. */ autoNumStartAt?: number; /** * Auto-numbering ORDINAL OFFSET: the zero-based distance of this paragraph * within its own numbered list, such that * `autoNumStartAt + paragraphIndex` is the ordinal to render. Despite the * name it is NOT the paragraph's position in the text body; the two agree * only for a list that starts at the first paragraph and is never * interrupted. * * It has to be the offset rather than the raw position because every * consumer that re-derives a marker from `BulletInfo` alone (the renderer's * `resolveParagraphBullet`, the Markdown converter's `resolveListMarker`) * computes `autoNumStartAt + paragraphIndex`. The load path resolves the * real sequence itself, restarting the count after any paragraph that * interrupts the list, and publishes the offset here so those consumers * land on the same number. With the raw position they did not, and BOTH * markers were painted ("3.1. Item"), because the paragraph builder drops * the parsed marker segment only when the two strings agree. * * Runtime-only: derived at parse time and never serialized. OOXML has no * counterpart (`a:buAutoNum` carries only `@type` and `@startAt`), so the * writer neither reads nor emits it. */ paragraphIndex?: number; /** Bullet font family from `a:buFont`. */ fontFamily?: string; /** * PANOSE font-matching hint from `a:buFont/@panose`. `a:buFont` is a * CT_TextFont, the same complex type as `a:latin`/`a:ea`/`a:cs`/`a:sym` * (which carry the equivalent `TextStyle.latinFontPanose` etc.), so a * bullet's own PANOSE/pitch-family/charset decide the fallback glyph * PowerPoint substitutes when the named typeface is missing. */ fontPanose?: string; /** Font pitch-and-family byte from `a:buFont/@pitchFamily`. */ fontPitchFamily?: number; /** Font character-set byte from `a:buFont/@charset`. */ fontCharset?: number; /** Bullet size as percentage of text font size from `a:buSzPct`. */ sizePercent?: number; /** Bullet size in points from `a:buSzPts`. */ sizePts?: number; /** Bullet color as hex string from `a:buClr`. */ color?: string; /** * Raw colour-choice XML captured from `` so that themed bullets * (`a:schemeClr`, `a:sysClr`, `a:prstClr`) round-trip with their original * identity rather than being flattened to `` on save. */ colorXml?: XmlObject; /** * Typed theme colour reference for the bullet colour, set when * {@link colorXml} is a plain `a:schemeClr`. Wins on save, same as * {@link TextStyle.colorRef}. */ colorRef?: PptxThemeColorRef; /** True when `a:buNone` explicitly suppresses bullets. */ none?: boolean; /** Picture bullet: relationship ID from `a:buBlip` → `a:blip[@r:embed]`. */ imageRelId?: string; /** Picture bullet: data URL of the embedded image. */ imageDataUrl?: string; /** * Raw `` XML captured at parse time. Carries the full blipFill * subtree (`a:tile`, `a:stretch`, `a:srcRect`, `a:blip > a:extLst`) so the * writer can emit the complete original definition rather than the bare * `a:blip[@r:embed]` mapping. When set, the writer prefers it over * {@link imageRelId} for emission. */ imageBlipFillXml?: XmlObject; /** When true, `` was specified — inherit the bullet font from * the run text, not from a buFont declaration. */ fontInherit?: boolean; /** When true, `` was specified — inherit the bullet colour from * the run text. */ colorInherit?: boolean; /** When true, `` was specified — inherit the bullet size from * the run text font size. */ sizeInherit?: boolean; /** * True when this bullet resolution came from the paragraph's OWN `a:pPr` * rather than the shape's `a:lstStyle`, an inherited placeholder, or the * master's `a:defPPr` / `p:txStyles`. `resolveParagraphBulletInfo` walks * that cascade and returns the first match, so without this flag a * writer that re-emits every resolved `BulletInfo` in full pins an * inherited bullet (e.g. a master `buFont="Arial"` / `buChar="•"`) onto * every paragraph's own `a:pPr` the moment the slide is rewritten. The * save path only writes the bullet group when this is `true`, mirroring * how `paragraphProperties` gates every other per-paragraph field. */ ownedByParagraph?: boolean; } /** * The right-click menu for the empty slide canvas (no element under the * cursor), as distinct from {@link ./context-menu-commands}'s per-element menu. * * Right-clicking empty canvas used to do nothing at all in every binding: React * and Vue both bailed out early (`getElementIdFromEvent` returns `null`, so the * handler just returns) rather than opening a menu, and the other three never * wired a handler for it either. PowerPoint offers Paste, Layout, Reset, * Format Background and view toggles (Grid and Guides, Ruler) from this menu; * this module is the one list every binding renders instead of five omissions. * * @module render/canvas-context-menu-commands */ /** Every command the empty-canvas context menu can offer, in no particular order. */ declare type CanvasContextMenuCommandId = 'paste' | 'layout' | 'reset-slide' | 'format-background' | 'grid-and-guides' | 'ruler'; /** Canvas dimensions in pixels. */ declare interface CanvasSize { width: number; height: number; } declare type Catalog = typeof RIBBON_CONTROL_CATALOG; /** A cell coordinate within a table (0-based). */ declare interface CellCoord { row: number; col: number; } /** The bounding rectangle of a cell selection (inclusive end coordinates). */ declare interface CellRect { startRow: number; startCol: number; endRow: number; endCol: number; } declare type ChangeCaseMode = 'sentence' | 'lower' | 'upper' | 'capitalize' | 'toggle'; /** Edit shape for axis-title font styling (matches the core op). */ export declare interface ChartAxisTitleStyleEdit { fontFamily?: string | null; fontSize?: number | null; fontBold?: boolean; fontColor?: string | null; } /** * `animation-timeline-build-descriptors` - staged-build (`p:bldChart` / * `p:bldDgm`) reveal descriptor types, split out of `animation-timeline-types` * to keep that module under the file-size limit. Re-exported from * `animation-timeline-types` so existing imports are unaffected. * * @module render/animation-timeline-build-descriptors */ /** * Normalized staged-reveal mode for a chart graphic frame, derived from the * OOXML `a:bldChart/@bld` (or `p:bldOleChart/@bld`) token: * - `asOne` the whole chart appears at once (`allAtOnce`). * - `bySeries` one data series is revealed per stage (`series`). * - `byCategory` one category is revealed per stage (`category`). * - `byElement` one series/category ELEMENT is revealed per stage * (`seriesElement` / `categoryElement`). */ declare type ChartBuildMode = 'asOne' | 'bySeries' | 'byCategory' | 'byElement'; /** The mutation helpers a chart inspector needs. */ export declare interface ChartEditing extends ChartOpEditing { patchChartData: (patch: Partial) => void; updateStyle: (patch: Partial) => void; updateAxis: (axisType: PptxChartAxisFormatting['axisType'], patch: Partial) => void; setSeriesColor: (index: number, color: string | null) => void; setSeriesTrendline: (index: number, trendline: PptxChartTrendline | null) => void; setSeriesErrorBars: (index: number, errBars: PptxChartErrBars | null) => void; /** Patch a single series (e.g. rename) in place, preserving the rest. */ updateSeries: (index: number, patch: Partial) => void; /** Rename one category label. */ updateCategoryLabel: (catIndex: number, value: string) => void; /** Set one numeric value from a raw input string (ignored if not finite). */ updateValue: (seriesIndex: number, catIndex: number, raw: string) => void; /** Append an empty series/category, or remove one by index. */ addSeries: () => void; removeSeries: (seriesIndex: number) => void; addCategory: () => void; removeCategory: (catIndex: number) => void; /** PowerPoint "Chart Filters": hide a currently-visible series. */ hideSeries: (seriesIndex: number) => void; /** PowerPoint "Chart Filters": restore a series it hid. */ restoreSeries: (filteredIndex: number) => void; /** "Value From Cells": edit one cached custom-label string for a series. */ setLabelsRangeCache: (seriesIndex: number, pointIndex: number, text: string) => void; } /** Edit shape for gridline line styling (matches the core op). */ export declare interface ChartGridlineStyleEdit { color?: string | null; width?: number | null; dashStyle?: string | null; } declare interface ChartInput { series: ChartSeriesInput[]; categories: string[]; /** ChartEx hierarchy levels in leaf-to-root XML order. */ categoryLevels?: string[][]; title?: string; hasLegend?: boolean; legendPosition?: 't' | 'b' | 'l' | 'r' | 'tr'; grouping?: 'clustered' | 'stacked' | 'percentStacked'; /** Bar series direction (`c:barDir`): vertical columns (default) or horizontal bars. */ barDirection?: 'col' | 'bar'; } /** Patch shape for a series marker (subset accepted by the core op). */ export declare interface ChartMarkerEdit { symbol?: PptxChartMarkerSymbol; size?: number; fillColor?: string; } /** The SDK-op mutation helpers a chart inspector needs. */ declare interface ChartOpEditing { setAxisLogScale: (axisType: PptxChartAxisFormatting['axisType'], opts: { enabled: boolean; base?: number; }) => void; setAxisTitleStyle: (axisType: PptxChartAxisFormatting['axisType'], edit: ChartAxisTitleStyleEdit) => void; setGridlineStyle: (axisType: PptxChartAxisFormatting['axisType'], which: 'major' | 'minor', edit: ChartGridlineStyleEdit) => void; setSeriesMarker: (index: number, marker: ChartMarkerEdit | null) => void; setSeriesType: (index: number, seriesType: PptxChartType | null) => void; setPointFill: (seriesIndex: number, pointIndex: number, color: string | null) => void; setPointExplosion: (seriesIndex: number, pointIndex: number, explosion: number | null) => void; setPointMarker: (seriesIndex: number, pointIndex: number, marker: ChartMarkerEdit | null) => void; setPointLabel: (seriesIndex: number, pointIndex: number, text: string | null) => void; } declare interface ChartOptions extends Partial {} /** * A chart embedded via a ``. * * Chart data is parsed from the related `chartN.xml` / `chartExN.xml` * parts inside the PPTX archive. */ declare interface ChartPptxElement extends PptxElementBase { type: 'chart'; chartData?: PptxChartData; /** Accessibility description from `p:nvGraphicFramePr/p:cNvPr/@descr`. */ altText?: string; /** Accessibility title from `p:nvGraphicFramePr/p:cNvPr/@title`. */ title?: string; /** Unrecognised graphicFrame extLst extensions, captured verbatim for round-trip. */ extensionXml?: PptxGraphicFrameExtension[]; } /** * Playback-time chart reveal state derived from AUTHORED `p:graphicEl` * indices (see `chart-reveal-descriptor`'s `resolveChartRevealDescriptor`), * rather than from click-count/time progress. Present on * {@link import('./animation-timeline-group').ElementAnimationState.chartReveal} * only when every fired chart-build step for the element carried index data; * a renderer prefers this over the progress-based `build`/`ElementBuildState` * path when present, since it reflects the real authored reveal set (correct * even for a reversed-order or gapped chart build), and falls back to `build` * when absent. */ declare interface ChartRevealDescriptor { /** * Whether the chart's background/axes/gridlines/legend should currently be * visible: always `true` when the chart's `animateBackground` is `false` * ("shown throughout"), otherwise `true` from the first revealed stage * onward. */ background: boolean; /** Whole series revealed by a `bldStep="series"` effect. */ series: ReadonlySet; /** Whole categories revealed by a `bldStep="category"` effect. */ categories: ReadonlySet; /** Individual cells revealed by a `bldStep="seriesEl"`/`"categoryEl"` effect. */ points: readonly ChartRevealPoint[]; } /** * One authored `p:graphicEl` reveal unit resolved onto a chart, per * `TimelineStepGraphicElement`'s "both indices set" case: a single (series, * category) cell revealed by a `bldStep="seriesEl"`/`"categoryEl"` effect. */ declare interface ChartRevealPoint { seriesIdx: number; categoryIdx: number; } declare interface ChartSeriesInput { name: string; values: number[]; color?: string; boxWhiskerOptions?: PptxChartBoxWhiskerOptions; histogramOptions?: PptxChartHistogramOptions; waterfallOptions?: PptxChartWaterfallOptions; regionMapOptions?: PptxChartRegionMapOptions; treemapOptions?: PptxChartTreemapOptions; } /** * `@keyframes` backing every cinematic transition. Fold into the injected * aggregate (`SLIDE_TRANSITION_KEYFRAMES`) so these animate wherever it is * injected. `pptx-tr-fade-in` (reused by wind/fracture/airplane incoming) is * already defined in the core block, so it is intentionally not redefined here. */ export declare const CINEMATIC_TRANSITION_KEYFRAMES: string; /** Parsed `clrChange` effect, as carried on `PptxImageEffects`. */ export declare type ClrChangeEffect = NonNullable; /** * Who asked for the deck that just finished loading, and what that means for a * room that already holds slides. * * Every binding brackets its content-load with an adoption check: when a load * lands while a collaboration session is up and the shared doc already has * slides, the ROOM wins and the freshly parsed deck is thrown away. That rule * exists for one case only - a late joiner whose bootstrap deck (the blank or * sample deck the host mounted the viewer with) finishes parsing after the * room's real slides arrived, which would otherwise clobber them with nothing * left to repair it, since the doc itself never changed. * * Applied to EVERY load it also swallows the deck a user deliberately opens * during a session. Joining a room and then opening a file left the viewer on * the room's blank starter deck: the file parsed, was committed, and was * immediately overwritten (reproduced in the vanilla demo - a 7-slide deck * opened in a room settled back to the room's 1 slide, and the bigger the file * the longer the window). Opening a file is an act of authorship, so it is * published to the room instead. * * @module render/collaboration-load-origin */ /** * Why a content load ran. * * - `bootstrap`: the deck the host handed the viewer at mount (`source`), or a * session restore. Nobody chose it during the session. * - `user`: opened during the session - File > Open, a recent file, a dropped * file, or a host calling the load API. */ declare type CollabLoadOrigin = 'bootstrap' | 'user'; /** * Real-time collaboration configuration. * * The same shape is accepted by every framework binding. */ declare interface CollaborationConfig { /** Unique identifier for the collaboration room (alphanumeric, hyphens, underscores). */ roomId: string; /** * WebSocket server URL for the Yjs provider (e.g. "wss://collab.example.com"). * Ignored (may be empty) for `externalSession` or when `transport` is `'webrtc'`. */ serverUrl: string; /** Transport to use. Defaults to `'websocket'`. */ transport?: CollaborationTransport; /** * Use the host's document, awareness and transport instead of creating a * provider. Transport, serverUrl, signaling and authToken are ignored. The * viewer only detaches its listeners and presence on stop; it never destroys * these resources. Keep this object stable and report readiness via subscribe. */ externalSession?: ExternalCollaborationSession; /** * WebRTC signaling server URLs (only used when `transport` is `'webrtc'`). * Defaults to y-webrtc's built-in public signaling list. Same-browser tabs * sync via BroadcastChannel regardless of signaling availability. */ signaling?: string[]; /** Display name for the local user. */ userName: string; /** Avatar URL for the local user (optional). */ userAvatar?: string; /** Hex colour for the local user's cursor/presence indicator. */ userColor?: string; /** Optional authentication token sent with the WebSocket handshake. */ authToken?: string; /** Role in the session; defaults to `'collaborator'`. */ role?: CollaborationRole; /** * Whether this client created the room or joined an existing room. Providers * do not use this value, but hosts can use it to avoid publishing local file * bytes when handling a join request. Omitted values retain the legacy * create-session behaviour. */ sessionIntent?: CollaborationSessionIntent; /** * Elected-writer write-back callback (Area 3 of the C3 hardening plan). * * When the local user has `role: 'owner'`, the binding debounces changes and * serializes the current Y.Doc state to a PPTX byte array, then calls this * callback so the host can persist the snapshot. Only one writer (the owner) * does this; other collaborators never trigger write-back, eliminating the * last-save-wins problem. */ onWriteBack?: (bytes: Uint8Array) => void; /** * Debounce delay (ms) between the last Y.Doc change and the write-back * invocation. Defaults to 5000 ms. Set to 0 to write back on every change * (not recommended for large documents). */ writeBackDebounceMs?: number; } declare interface CollaborationInlineSnapshot extends CollaborationTextSnapshot { readonly inline: InlineTextEditSnapshot; } declare interface CollaborationLivePatcher { /** Bind a mounted native editor; its handle must be disposed on unmount. */ beginTextEdit?: (slideId: string | undefined, elementId: string, onChange?: () => void, ownsModel?: (element: PptxElement) => boolean) => CollaborationTextTarget | undefined; /** Attach a live doc (or `null` to go dormant). Pending patches are dropped. */ configure: (doc: YDocLike | null, factories: YjsFactories | null, /** Publish synchronously when the host may revoke write readiness at any time. */ immediate?: boolean) => void; /** True when a doc + factories are attached, i.e. patches will be written. */ isActive: () => boolean; /** Queue interim geometry for an element. */ patchGeometry: (slideId: string | undefined, elementId: string, geometry: LiveGeometryPatch) => void; /** Queue interim text for an element (remapped over `source`'s segments). */ patchText: (slideId: string | undefined, elementId: string, text: string, source?: LiveTextSource) => void; /** Write everything queued right now (call on gesture end / edit commit). */ flush: () => void; /** Drop pending work, cancel timers and detach the doc. */ dispose: () => void; } /** Collaboration role within a session. */ declare type CollaborationRole = 'owner' | 'collaborator' | 'viewer'; /** How the local user entered a collaboration session. */ declare type CollaborationSessionIntent = 'create' | 'join'; declare interface CollaborationShellState { canEdit: boolean; status: ConnectionStatus; remoteUsers: readonly SanitizedPresence[]; connectedCount: number; } declare interface CollaborationTextSession { applyLocalDelta: (delta: readonly DeltaOp[], edit?: LocalTextEdit) => boolean; readMerged: () => CollaborationTextSnapshot | undefined; adoptMerged: (snapshot: CollaborationTextSnapshot) => boolean; /** Capture an offset in the last painted/local draft, not the newer remote string. */ bookmark: (index: number, association: number) => () => number | null; dispose: () => void; } /** Opaque acknowledgement identity for an exact remote snapshot painted by an adapter. */ declare interface CollaborationTextSnapshot { readonly delta: readonly DeltaOp[]; } /** A mounted editor owns this handle, never the document or its provider. */ declare interface CollaborationTextTarget extends CollaborationTextSession { readMerged: () => CollaborationInlineSnapshot | undefined; /** A bookmark follows character identity rather than a mutable numeric offset. */ bookmark: (index: number, association: number) => () => number | null; } /** * Collaboration transport. * * - `'websocket'` (default): y-websocket against `serverUrl`. * - `'webrtc'`: y-webrtc peer-to-peer; needs no document server. Peers meet * through the `signaling` servers (WebRTC signaling only, no document data) * and same-browser tabs additionally sync via BroadcastChannel even without * any signaling server, which makes this mode usable from static hosting. */ declare type CollaborationTransport = 'websocket' | 'webrtc'; declare interface CompareResult { diffs: SlideDiff[]; baseSlideCount: number; compareSlideCount: number; addedCount: number; removedCount: number; changedCount: number; unchangedCount: number; } /** * Pure next-selection computation for a cell click. Shift+click within the same * table (anchored at the previous selection) yields a rectangular multi-cell * selection expanded across any merges it overlaps; any other click selects the * single clicked cell. Mirrors React's `table-render` onClick branch. */ export declare function computeCellSelection(prev: TableSelectionState | null, elementId: string, rowIndex: number, columnIndex: number, shiftKey: boolean, tableData: PptxTableData): TableSelectionState; /** Compute current counts rather than trusting potentially stale app.xml totals. */ export declare function computeDocumentStatistics(slides: readonly PptxSlide[], coreProperties: PptxCoreProperties | undefined): DocumentStatistics; /** * Compute the elapsed time (ms) between a start timestamp and `now`, subtracting * any accumulated paused time and the open pause segment. Returns 0 when not * started. Never negative. * * @param startTime - Timestamp (ms) the timer started, or `null` if not started. * @param now - The reference "now" timestamp (ms). * @param pausedAccumulatedMs - Already-accumulated paused time (ms). * @param pauseStart - Timestamp (ms) the current pause began, or `null`. */ export declare function computeElapsed(startTime: number | null, now: number, pausedAccumulatedMs?: number, pauseStart?: number | null): number; /** * Connection site (`a:cxn`) on a custom geometry. * * Defines a point on a custom shape that connectors may snap to. * * @example * ```ts * const cxn: ConnectionSite = { ang: "0", posX: "0", posY: "hd2" }; * // => satisfies ConnectionSite * ``` */ declare interface ConnectionSite { /** Approach angle (`@_ang`) — formula or literal degree-1/60000 value. */ ang?: string; /** Site position X from `a:pos/@_x`. */ posX?: string; /** Site position Y from `a:pos/@_y`. */ posY?: string; } /** Connection lifecycle states for the Yjs WebSocket provider. */ declare type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error'; /** * Arrow head types for connector start/end. * * Maps to `a:headEnd/@type` and `a:tailEnd/@type` in OOXML. * * @example * ```ts * const arrow: ConnectorArrowType = "triangle"; * // => "triangle" — one of: none | triangle | stealth | diamond | oval | arrow * ``` */ declare type ConnectorArrowType = 'none' | 'triangle' | 'stealth' | 'diamond' | 'oval' | 'arrow'; /** * Connector connection point reference — links a connector endpoint to a * specific shape on the slide. * * When both `shapeId` and `connectionSiteIndex` are set, the connector * end snaps to that shapes’s connection site and “follows” the shape when * it is moved. * * @example * ```ts * const start: ConnectorConnectionPoint = { * shapeId: "shape_1", * connectionSiteIndex: 2, * }; * // => { shapeId: "shape_1", connectionSiteIndex: 2 } satisfies ConnectorConnectionPoint * ``` */ declare interface ConnectorConnectionPoint { /** ID of the shape this connector endpoint is attached to. */ shapeId?: string; /** Connection site index on the target shape (0-based). */ connectionSiteIndex?: number; } declare interface ConnectorOptions extends Partial { type?: 'straight' | 'bent' | 'curved'; stroke?: StrokeInput; startArrow?: ConnectorArrowType; endArrow?: ConnectorArrowType; from?: { elementId: string; site: number; }; to?: { elementId: string; site: number; }; } /** * A connector (straight, bent, or curved line between shapes). * * Connector endpoints can snap to specific shapes via * `shapeStyle.connectorStartConnection` / `connectorEndConnection`. * * @example * ```ts * const line: ConnectorPptxElement = { * type: "connector", * id: "cxn_1", x: 100, y: 100, width: 200, height: 0, * shapeStyle: { * strokeColor: "#333", * connectorEndArrow: "triangle", * }, * }; * // => satisfies ConnectorPptxElement * ``` */ declare interface ConnectorPptxElement extends PptxElementBase, PptxTextProperties, PptxShapeProperties, PptxNonVisualDescription { type: 'connector'; } /** * Source of the container element observed for container-based breakpoints: * either a Vue `Ref` (e.g. a `templateRef`) or a plain getter. Resolved lazily * each time the observer (re)reads it so late-mounted refs are picked up. */ export declare type ContainerSource = Ref | (() => HTMLElement | null | undefined); /** * A single ink stroke within a {@link ContentPartPptxElement}. */ declare interface ContentPartInkStroke { path: string; color: string; width: number; opacity: number; /** * Per-point pressure values (0-1) for this stroke. * * When present, the renderer uses these values to produce * variable-width strokes that reflect stylus/pen pressure. */ pressures?: number[]; /** * Per-point pen-tilt lean direction (radians), decoded from the source * InkML's `OTx`/`OTy` tilt-offset channels or its `AZIMUTH` channel. * * When present (paired with {@link tiltMagnitudes}), the renderer widens * each point perpendicular to the lean direction, approximating a * calligraphic (chisel-tip) nib. Absent when the source declared no tilt * channel, in which case rendering is unaffected. */ tiltAngles?: number[]; /** * Per-point pen-tilt strength (0 upright, 1 maximally leaned), paired with * {@link tiltAngles}. */ tiltMagnitudes?: number[]; /** * Which InkML channel pair {@link tiltAngles}/{@link tiltMagnitudes} were * decoded from: `'azimuthAltitude'` when the source declared `AZIMUTH` * (optionally paired with `ALTITUDE`); omitted (implying `OTx`/`OTy`, i.e. * `'vector'`) otherwise, including for tilt this library itself captured * from the Draw tool's `PointerEvent.tiltX`/`tiltY`. * * A save that has to rewrite this content part's InkML (see * `inkml-content-part-writer.ts`) uses this to re-declare the SAME channel * pair the file already used, rather than always converting to `OTx`/`OTy`; * the rendered lean is identical either way; only the written channel * NAMES differ. */ tiltEncoding?: 'vector' | 'azimuthAltitude'; /** * Per-point timestamps (milliseconds), decoded from the source InkML * trace's `T` channel when it declared one. * * Absent for the overwhelming majority of real decks: PowerPoint's own * SaveAs output declares only `X`/`Y` and has no per-point time channel at * all (see `contentpart-real-ink-roundtrip.test.ts`'s fixture), so this is * populated only for InkML sources that genuinely author one (a captured * digitizer session, OneNote, a Surface Hub export). When present, ink * replay ("watch the ink get drawn") uses each stroke's own first/last * timestamp to time its reveal instead of the fixed per-stroke cascade; see * `pptx-viewer-shared`'s `render/ink-replay-timeline.ts`. */ pointTimestamps?: number[]; } /** * A content-part element wrapped in `mc:AlternateContent`. * * Typically contains ink strokes from modern PowerPoint pen/highlighter. */ declare interface ContentPartPptxElement extends PptxElementBase { type: 'contentPart'; /** Ink strokes contained in this content part. */ inkStrokes?: ContentPartInkStroke[]; /** Package path of the related InkML part. */ inkPartPath?: string; /** Parsed InkML root retained for unknown-node preservation on dirty save. */ inkPartRawXml?: XmlObject; } /** Every command a canvas context menu can offer, in no particular order. */ declare type ContextMenuCommandId = 'copy' | 'cut' | 'paste' | 'duplicate' | 'edit-text' | 'edit-points' | 'bring-forward' | 'send-backward' | 'bring-front' | 'send-back' | 'ai-ask' | 'ai-fix' | 'comment' | 'hyperlink' | 'table-insert-row-above' | 'table-insert-row-below' | 'table-delete-row' | 'table-insert-col-left' | 'table-insert-col-right' | 'table-delete-col' | 'table-merge-selected' | 'table-merge-right' | 'table-merge-down' | 'table-split' | 'group' | 'ungroup' | 'crop' | MergeShapesCommandId | 'save-as-picture' | 'edit-alt-text' | 'size-and-position' | 'format-shape' | 'delete'; /** * ContextMenu: generic right-click menu for the Vue editor. * * Vue port of the React `ContextMenu` component (see * `packages/react/src/viewer/components/ContextMenu.tsx`), generalised into a * data-driven menu: the caller supplies the item list and maps `select(id)` * back to editor operations. */ declare interface ContextMenuItem { /** Stable id emitted via `select`. Ignored for separators. */ id: string; /** Visible label. */ label: string; /** When true the item is shown greyed-out and is non-interactive. */ disabled?: boolean; /** When true the entry renders as a divider instead of a button. */ separator?: boolean; /** * A checkbox-style toggle (Grid and Guides, Ruler) in this state, rather * than a one-shot command. Omitted for ordinary commands, which keep * `role="menuitem"`. */ checked?: boolean; } /** Reactive open/position/target state for the element context menu. */ export declare interface ContextMenuState { open: boolean; x: number; y: number; elementId: string | null; } export declare function countWords(text: string | undefined): number; /** Build a new stroke for the given pen/highlighter tool at a start point. */ export declare function createStroke(tool: 'pen' | 'highlighter', x: number, y: number, penColor: string, highlighterColor: string): AnnotationStroke; /** What a crop edit writes back onto the picture element. */ declare type CropElementUpdate = CropInsets & CropRect; /** The four `a:srcRect` insets as fractions of the image (negative pads). */ declare interface CropInsets { cropLeft: number; cropTop: number; cropRight: number; cropBottom: number; } /** An axis-aligned rectangle in slide pixels. */ declare interface CropRect { x: number; y: number; width: number; height: number; } /** Minimal CSS-properties shape: kebab-case property → value. */ export declare type CSSProperties = Record; /** * A single sub-path in a custom geometry definition (maps to one `a:path`). * * @example * ```ts * const path: CustomGeometryPath = { * width: 100, * height: 100, * segments: [ * { type: "moveTo", pt: { x: 0, y: 0 } }, * { type: "lineTo", pt: { x: 100, y: 100 } }, * ], * }; * // => satisfies CustomGeometryPath * ``` */ declare interface CustomGeometryPath { /** Coordinate-space width for this sub-path. */ width: number; /** Coordinate-space height for this sub-path. */ height: number; /** Ordered list of drawing segments. */ segments: CustomGeometrySegment[]; /** Path fill mode (`a:path/@fill`): norm, lighten, lightenLess, darken, darkenLess, none. */ fillMode?: 'norm' | 'lighten' | 'lightenLess' | 'darken' | 'darkenLess' | 'none'; /** Whether the path is stroked (`a:path/@stroke`). */ stroke?: boolean; /** 3D extrusion compatibility (`a:path/@extrusionOk`). */ extrusionOk?: boolean; } /** * A single point in a custom geometry path. * * @example * ```ts * const pt: CustomGeometryPoint = { x: 100, y: 200 }; * // => satisfies CustomGeometryPoint * ``` */ declare interface CustomGeometryPoint { x: number; y: number; } /** * Auxiliary raw XML preserved from `a:custGeom` for round-trip serialization. * These are stored opaquely so adjustment guides, handles, connection sites, * and the text rectangle are not lost when a custGeom is edited and saved. */ declare interface CustomGeometryRawData { /** Raw `a:avLst` XML content (adjustment value list). */ avLstXml?: unknown; /** Raw `a:gdLst` XML content (guide list). */ gdLstXml?: unknown; /** Raw `a:ahLst` XML content (adjustment handles). */ ahLstXml?: unknown; /** Raw `a:cxnLst` XML content (connection sites). */ cxnLstXml?: unknown; /** Raw `a:rect` XML content (text rectangle). */ rectXml?: unknown; /** * Raw `a:pathLst` XML content: every `a:path`'s formula-bearing `a:pt` * x/y attributes, `a:arcTo` params, `a:close`, and per-path `@w`/`@h`/ * `@fill`/`@stroke`/`@extrusionOk`, preserved verbatim (not the * parse-time-resolved numbers in `customGeometryPaths`). Lets a live * `shapeAdjustments` drag re-evaluate the outline against the CURRENT * guide values instead of the ones baked in at parse time; see * `geometry/custom-geometry-live-eval.ts`. */ pathLstXml?: unknown; } /** * A segment within a custom geometry path. * * Discriminated union over `type` — can be a moveTo, lineTo, * cubic Bézier, quadratic Bézier, or close command. * * @example * ```ts * const segments: CustomGeometrySegment[] = [ * { type: "moveTo", pt: { x: 0, y: 0 } }, * { type: "lineTo", pt: { x: 100, y: 0 } }, * { type: "lineTo", pt: { x: 100, y: 100 } }, * { type: "close" }, * ]; * // => satisfies CustomGeometrySegment[] * ``` */ declare type CustomGeometrySegment = { type: 'moveTo'; pt: CustomGeometryPoint; } | { type: 'lineTo'; pt: CustomGeometryPoint; } | { type: 'cubicBezTo'; pts: [CustomGeometryPoint, CustomGeometryPoint, CustomGeometryPoint]; } | { type: 'quadBezTo'; pts: [CustomGeometryPoint, CustomGeometryPoint]; } | { type: 'arcTo'; /** Horizontal radius of the ellipse. */ wR: number; /** Vertical radius of the ellipse. */ hR: number; /** Start angle in 60000ths of a degree. */ stAng: number; /** Sweep angle in 60000ths of a degree. */ swAng: number; } | { type: 'close'; }; /** * Typed text rectangle (`a:rect`) on a custom geometry. * * Each edge is the formula or literal string preserved from the source XML * (`"l"`, `"t"`, `"r"`, `"b"`, or any guide name / formula). */ declare interface CustomGeometryTextRect { /** Left edge formula reference (`@_l`). */ l?: string; /** Top edge (`@_t`). */ t?: string; /** Right edge (`@_r`). */ r?: string; /** Bottom edge (`@_b`). */ b?: string; } /** A debounced function plus its `cancel` / `flush` controls. */ export declare interface DebouncedCallback { (...args: A): void; /** Discard any pending trailing call. */ cancel: () => void; /** Run any pending trailing call right away. */ flush: () => void; } /** * What the Protect-Presentation UI knows at save time. `password` is the secret * the dialog captured; `passwordProtected` is the separate "is protected" flag * some bindings track for the badge. When the flag is explicitly `false` the * deck saves in the clear even if a stale secret is still around, so removing * a password can never leave the next save encrypted. * * `purpose` defaults to `'user-file'`; see {@link DeckSavePurpose} for why * `'recovery-snapshot'` overrides the password. */ declare interface DeckSaveIntent { password?: string | null; passwordProtected?: boolean; purpose?: DeckSavePurpose; } /** * Why the deck is being serialised, which is a separate question from whether * the user protected it. * * - `user-file` (the default): the bytes leave the viewer as a file. Save, * Save As, Export, the host-facing `getContent()`. Protection applies. * - `recovery-snapshot`: the bytes exist only so the viewer can read them back. * The autosave crash-recovery snapshot in IndexedDB, and the internal * re-serialise-then-reload cycle behind "apply theme". Protection does NOT * apply: these are always written in the clear. * * ## Why a recovery snapshot must stay plaintext * * Nothing that reads a snapshot back has a password to give it. * `readBackstageRecentFile`, `restoreSessionDeck` and the Version History * panel's Restore all hand `record.data` straight to `PptxHandler.load()` with * no `password` option, and an encrypted package refuses to open without one * (`EncryptedFileError`). So an encrypted snapshot is not an inconvenience, it * is unreadable: the moment the user turns on protection their crash-recovery * data is silently destroyed, which is the exact opposite of what autosave is * for. * * Encrypting it "properly" is not available either. Decrypting on recovery * means the key has to outlive the crash the snapshot exists for, so it would * have to sit in the same IndexedDB / localStorage as the snapshot itself, * next to the ciphertext it unlocks. That is not a security boundary, it is * theatre. Prompting the user instead only works if they remember the password * of a deck they lost, which is precisely the moment they will not. * * ## The tradeoff this accepts (deliberately, not by omission) * * A password-protected deck DOES leave its content in cleartext at rest in the * origin's IndexedDB. Anyone with the browser profile, or any script running on * the origin, can read it. What limits the exposure: snapshots are scoped to * the origin and profile, aged out by the store, and clearable from * File > Account > Storage & Privacy (`clearLocalStorageData`). A user who * cannot accept plaintext at rest should switch AutoSave off, which stops the * snapshot being written at all. * * The rejected alternative was "skip autosave entirely while a password is * set". It removes the plaintext, but it also removes crash recovery without * telling anyone, so a crash loses the whole editing session. Losing data * quietly is the failure mode we are fixing, not a fix for it. */ declare type DeckSavePurpose = 'user-file' | 'recovery-snapshot'; /** Default cap on retained snapshots (oldest dropped first when exceeded). */ export declare const DEFAULT_MAX_VERSIONS = 50; /** * Default Morph duration (ms) for a transition that declares NEITHER an * explicit `p14:dur` (which lands in `durationMs` and always wins) NOR a legacy * `spd` speed (see {@link TRANSITION_SPEED_DURATION_MS}). * * A Morph that declares nothing carries no duration hint at all, and desktop * PowerPoint then plays it at its own 0.5s fallback (the Duration box shows * 0.50 for such slides and the transition measures at half a second); the * previous 1.0s/2.0s defaults made those decks play at double PowerPoint * speed. */ export declare const DEFAULT_MORPH_DURATION_MS = 500; /** All off: the safe default outside `PowerPointViewer` (tests, isolated thumbnails). */ export declare const DEFAULT_RENDERING_3D_FLAGS: Rendering3DFlags; /** * Default transition duration (ms) when the transition omits `durationMs`. This * is the React/Vue default consumed by `resolveSlideTransition`. The Angular * binding uses its own (smaller, floored) duration policy. */ export declare const DEFAULT_TRANSITION_DURATION_MS = 1000; declare type DefaultExportFormat = 'pptx' | 'pdf' | 'png'; /** * collaboration-text-codec.ts: TextSegment[] <-> Y.Text delta codec used by the * collaboration sync layer. Split out of collaboration-sync.ts to keep both * modules focused. * * Exports: * - DeltaOp / YTextLike: structural Yjs text interfaces (no yjs import) * - encodeTextBody: write TextSegment[] into a live YTextLike * - encodeSegmentsToDelta: pure simulation of the delta Y.Text would produce * - decodeDelta / decodeTextBody: delta -> TextSegment[] * - isYTextLike: runtime guard */ declare interface DeltaOp { insert?: unknown; attributes?: Record; } /** Device orientation as reported by the screen / viewport aspect ratio. */ export declare type DeviceOrientation = 'portrait' | 'landscape'; /** * Normalized staged-reveal mode for a SmartArt diagram, derived from the OOXML * `a:bldDgm/@bld` or `p:bldDgm/@bld` token: * - `asOne` the whole diagram appears at once (`whole` / `allAtOnce`). * - `byOne` one node is revealed per stage (`one`, and the assorted * `depthBy*` / `breadthBy*` / directional traversals). * - `byLvl` levels are revealed one element at a time (`lvlOne`). * - `byLvlAtOnce` a whole level is revealed per stage (`lvlAtOnce`). */ declare type DiagramBuildMode = 'asOne' | 'byOne' | 'byLvl' | 'byLvlAtOnce'; /** * Playback-time SmartArt diagram reveal state derived from AUTHORED * `p:graphicEl/p:dgm/@id` indices (see `diagram-reveal-descriptor`'s * `resolveDiagramRevealDescriptor`), rather than from click-count/time * progress. Present on * {@link import('./animation-timeline-group').ElementAnimationState.diagramReveal} * only when every fired diagram-build step for the element carried * `p:graphicEl` data. A SmartArt renderer prefers this over the * progress-based `build` / {@link ElementBuildState} path when present, since * it reflects the real authored reveal set (correct even for a * reversed-order or by-branch build), and falls back to `build` when absent. */ declare interface DiagramRevealDescriptor { /** * Whether the diagram's background/connector chrome should currently be * visible: `true` once any node-revealing or background-revealing * (`bldStep="bg"`) step has fired. */ background: boolean; /** Data-model point ids (`PptxSmartArtNode.id`) revealed so far. */ nodeIds: ReadonlySet; } declare type DisplayOptimization = 'appearance' | 'compatibility'; /** Axis along which {@link distributeElements} evenly spaces a selection. */ declare type DistributeAxis = 'horizontal' | 'vertical'; /** * Payload emitted on save. Mirrors the React `onSave(core, custom, app?)` * signature, collapsed into a single patch object so the host can apply it in * one call. `app` is only present when manager/company changed. */ declare interface DocumentPropertiesSavePatch { /** Full edited core-properties draft. */ core: PptxCoreProperties; /** Full edited custom-properties list. */ custom: PptxCustomProperty[]; /** Edited app properties (manager/company); omitted when unchanged. */ app?: Pick; } /** Live document statistics derived from the editable slide model. */ export declare interface DocumentStatistics { slideCount: number; hiddenSlideCount: number; noteCount: number; elementCount: number; wordCount: number; paragraphCount: number; created: string | undefined; modified: string | undefined; revision: string | undefined; lastModifiedBy: string | undefined; } /** Active drawing/inking tool. Mirrors React `DrawingTool`. */ declare type DrawingTool = 'select' | 'pen' | 'highlighter' | 'eraser' | 'freeform'; /** Easing applied to every transition animation. */ export declare const EASE = "ease-in-out"; /** Which of the two behaviours a paragraph asks for. */ declare interface EastAsianBreakOptions { /** `a:pPr/@hangingPunct="1"`. */ hangingPunctuation: boolean; /** `a:pPr/@eaLnBrk="0"`: break between any two East Asian characters. */ breakAnywhere: boolean; } export declare interface EditorHistoryResult { /** True when there is at least one snapshot to undo to. */ canUndo: ComputedRef; /** True when there is at least one snapshot to redo to. */ canRedo: ComputedRef; /** * Snapshot the current `slides.value` onto the undo stack and clear the redo * stack. Call this immediately **before** committing a mutating change. */ pushHistory: (label?: string) => void; /** Revert to the previous snapshot, pushing the current state onto redo. */ undo: () => void; /** Re-apply the next snapshot, pushing the current state back onto undo. */ redo: () => void; /** Drop all undo/redo history (e.g. when new content is loaded). */ clearHistory: () => void; /** * Apply a new File > Options > Advanced > "Maximum number of undos" value * at runtime (`resolveHistoryDepth`). Trims the past stack immediately if * the new limit is smaller. */ setMaxDepth: (depth: number) => void; } /** A logical editor command produced by one key press. */ declare type EditorKeyActionName = 'undo' | 'redo' | 'copy' | 'cut' | 'paste' | 'duplicate' | 'delete' | 'selectAll' | 'group' | 'ungroup' | 'nudge' | 'prevSlide' | 'nextSlide' | 'escape' | 'find' | 'findReplace' | 'toggleShortcuts' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'alignJustify' | 'increaseFontSize' | 'decreaseFontSize' | 'copyFormat' | 'pasteFormat' | 'newSlide' | 'hyperlink' | 'clearFormatting' | 'cycleSelectionNext' | 'cycleSelectionPrev' | 'pasteSpecial'; export declare interface EditorOperations { /** Resolved active slide (or `undefined` when the index is out of range). */ activeSlide: ComputedRef; /** Currently-selected element ids (owned internally if not supplied as input). */ selectedElementIds: Ref; /** Append an element to the active slide and select it. */ addElement: (element: PptxElement) => void; /** Shallow-merge `updates` into the element with `elementId` on the active slide. */ updateElement: (elementId: string, updates: Partial) => void; /** Remove an element from the active slide and drop it from the selection. */ removeElement: (elementId: string) => void; /** Patch an element's geometry (x/y/width/height/rotation). */ transformElement: (elementId: string, transform: ElementTransform) => void; /** Alias of {@link transformElement}: mirrors the React "move" semantics. */ moveElement: (elementId: string, transform: ElementTransform) => void; /** * Deep-clone an element (new ids via core `duplicateElement`), offset it * slightly, append it, and select the copy. Returns the new element's id. */ duplicateElement: (elementId: string) => string | undefined; /** Swap an element one step later in z-order (towards the front). */ bringForward: (elementId: string) => void; /** Swap an element one step earlier in z-order (towards the back). */ sendBackward: (elementId: string) => void; /** Move an element in front of every sibling on its layer. */ bringToFront: (elementId: string) => void; /** Move an element behind every sibling on its layer. */ sendToBack: (elementId: string) => void; /** Move an element to an explicit index within the active slide's z-order. */ reorder: (elementId: string, toIndex: number) => void; /** * Update an element's text. For `smartArt` elements a `nodeId` targets a * specific node via core `updateSmartArtNodeText`; for text/shape elements the * `text` field (and every text segment's text) is replaced. */ updateElementText: (elementId: string, text: string, nodeId?: string) => void; } /** Every command the Edit Points right-click menu can offer. */ declare type EditPointsCommandId = 'add-point' | 'delete-point' | 'delete-segment' | 'open-path' | 'close-path' | 'smooth-point' | 'straight-point' | 'corner-point' | 'straight-segment' | 'curved-segment' | 'exit'; /** Typed CT_AlphaOutsetEffect with original XML retained for lossless edits. */ declare interface EffectDagAlphaOutset { kind: 'alphaOutset'; radiusEmu?: number; xml: XmlObject; } declare interface EffectDagBlend { kind: 'blend'; mode: EffectDagBlendMode; container: EffectDagContainer; } declare type EffectDagBlendMode = 'darken' | 'lighten' | 'mult' | 'over' | 'screen'; /** Typed CT_BlurEffect with its original payload retained for lossless edits. */ declare interface EffectDagBlur { kind: 'blur'; radiusEmu?: number; grow?: boolean; xml: XmlObject; } declare interface EffectDagContainer { kind: 'cont'; type: EffectDagContainerType; name?: string; children: EffectDagNode[]; } declare type EffectDagContainerType = 'sib' | 'tree'; declare type EffectDagNode = EffectDagContainer | EffectDagBlend | EffectDagXfrm | EffectDagRelOff | EffectDagBlur | EffectDagAlphaOutset | EffectDagPresetShadow | EffectDagRawLeaf; /** Typed CT_PresetShadowEffect with colour and extension XML retained verbatim. */ declare interface EffectDagPresetShadow { kind: 'prstShdw'; preset?: `shdw${number}`; distanceEmu?: number; direction?: number; xml: XmlObject; } declare interface EffectDagRawLeaf { kind: 'raw'; tag: string; xml: Record; } declare interface EffectDagRelOff { kind: 'relOff'; tx?: number; ty?: number; } declare interface EffectDagXfrm { kind: 'xfrmEffect'; sx?: number; sy?: number; kx?: number; ky?: number; tx?: number; ty?: number; } /** Snapshot of a single element's animation state at a point in the timeline. */ declare interface ElementAnimationState { /** Whether the element should be visible. */ visible: boolean; /** CSS animation shorthand to apply (undefined = no active animation). */ cssAnimation: string | undefined; /** * Staged-build reveal state, present only when the active animation builds a * chart or SmartArt diagram in stages (`p:bldChart` / `p:bldDgm`) rather than * revealing the whole element at once. A staged renderer multiplies * `build.progress` (0..1) by its own series / category / level COUNT to * decide how many stages are revealed at the current playback time; see * {@link import('./animation-build').revealedStageCount}. Absent for ordinary * whole-element entrances, so existing renderers are unaffected. */ build?: ElementBuildState; /** * Authored-index chart reveal state (see {@link ChartRevealDescriptor}), * present only when every fired chart-build step for this element carried * `p:graphicEl` index data. A chart renderer prefers this over `build` when * present; `chart-build`'s `resolveRevealedChartData` picks between the two. */ chartReveal?: { mode: ChartBuildMode; descriptor: ChartRevealDescriptor; }; /** * Authored-index SmartArt diagram reveal state (see * {@link DiagramRevealDescriptor}), present only when every fired * diagram-build step for this element carried `p:graphicEl` node-id data. * `diagram-build`'s `resolveRevealedSmartArtNodes` prefers this over `build` * when present. */ diagramReveal?: { mode: DiagramBuildMode; descriptor: DiagramRevealDescriptor; }; /** * True when an active `p:animClr` color animation targets this shape's fill. * A vector renderer should then paint the fill with `fill: inherit` so the * wrapper-level colour keyframes cascade to the SVG path. Absent/false means * no active fill-colour animation. */ animatesFill?: boolean; /** * True when an active `p:animClr` color animation targets this shape's * stroke. A vector renderer should then paint the stroke with * `stroke: inherit`. Absent/false means no active stroke-colour animation. */ animatesStroke?: boolean; /** * Active discrete font-style / colour / size override (see * {@link import('./animation-timeline-step').TimelineStep.textStyle}) a * font-style emphasis effect currently applies to this element's text, * OVERRIDING the runs' own inline bold/italic/underline/size/colour. * `animation-playback-engine.ts` writes this on step start and again on * cleanup (held in full when the effect's `p:cTn/@fill` holds its end * state, otherwise reverted); a text renderer maps it onto its run markup * via `buildTextStyleOverrideCss` (`animation-text-style-css.ts`). Absent * means no font-style emphasis effect is currently active on this element. */ textStyle?: TextStyleAnimationDescriptor; } /** * Playback-time staged-build state surfaced on * {@link import('./animation-timeline-group').ElementAnimationState}. * `progress` is the 0..1 fraction of the build revealed at the current * playback time; a consumer maps it to its own item COUNT (see * `revealedStageCount`). */ declare type ElementBuildState = { kind: 'chart'; mode: ChartBuildMode; progress: number; } | { kind: 'diagram'; mode: DiagramBuildMode; progress: number; }; declare interface ElementChange { elementId: string; label: string; kind: ElementChangeKind; description: string; } declare type ElementChangeKind = 'added' | 'removed' | 'moved' | 'resized' | 'textChanged'; /** Opaque clipboard payload: only its presence gates the Paste button. */ declare type ElementClipboardPayload = Record; /** Position and size in pixels. Converted to EMU internally when needed. */ declare interface ElementPosition { x: number; y: number; width: number; height: number; rotation?: number; } /** * useEditorOperations: element CRUD + transform operations over the active * slide of a reactive `PptxSlide[]`. * * This is the Vue port of the editing foundation that lives across the React * `useElementOperations` / `useClipboardHandlers` / `useGroupAlignLayerHandlers` * hooks. It is deliberately PURE of DOM and component concerns: it operates only * on the reactive slide model plus a current-slide-index ref, and threads every * mutation through a `pushHistory` callback (typically `useEditorHistory`'s * `pushHistory`) so the change is undoable. * * Mutation strategy (immutable, snapshot-first): * 1. call `pushHistory()` to snapshot the pre-mutation state, * 2. build a brand-new `PptxSlide[]` (active slide rebuilt with new elements), * 3. assign it to `slides.value`. * * Element cloning / creation always defers to the core helpers (`cloneSlide`, * `cloneElement`, `duplicateElement`, `updateSmartArtNodeText`) rather than * re-implementing them. */ /** Geometry/transform fields that {@link EditorOperations.transformElement} can patch. */ export declare interface ElementTransform { x?: number; y?: number; width?: number; height?: number; rotation?: number; } /** Signature of the lazily-loaded GIF encoder (see `gif-encoder.ts`). */ export declare type EncodeGif = (frames: GifFrame[], delayCs: number) => Uint8Array; /** * Type definitions for OOXML encryption and decryption. * * Contains all interfaces and type aliases used by the OOXML crypto modules. * * @module ooxml-crypto-types */ /** Supported encryption algorithms. */ declare type EncryptionAlgorithm = 'AES128' | 'AES256'; /** Encryption options for creating encrypted files. */ declare interface EncryptionOptions { /** The encryption algorithm to use (defaults to AES256). */ algorithm?: EncryptionAlgorithm; /** Number of hash iterations for key derivation (defaults to 100000). Lower values speed up tests. */ spinCount?: number; /** * Which encryption scheme to write (defaults to 'agile'). 'standard' * writes the ECMA-376 Standard scheme (Office 2007-compatible: a single * password-derived AES-CBC key with a zero IV over the whole package), * mirroring the scheme this library already knows how to decrypt. */ encryptionScheme?: EncryptionScheme; } /** * Which OOXML encryption scheme to write when creating a password-protected * file. Real PowerPoint can write and open either scheme; this library * defaults to 'agile' (Office 2010+), matching PowerPoint's own default. */ declare type EncryptionScheme = 'agile' | 'standard'; export declare const ERASER_RADIUS = 16; /** * Remove any stroke that passes within `radius` of `(x, y)`. Returns a new * array (never mutates the input); identity-equal to the input when nothing * was erased. */ export declare function eraseStrokesAtPoint(strokes: AnnotationStroke[], x: number, y: number, radius?: number): AnnotationStroke[]; /** Options for the multi-slide PDF export (progress + cooperative cancel). */ export declare interface ExportPdfOptions { /** Capture-phase progress callback: `(currentSlide, totalSlides)`. */ onProgress?: ExportProgress; /** Abort the export early; the loop checks this between slides. */ signal?: AbortSignal; } /** Per-slide progress callback: `(currentSlideIndex, totalSlides)`. */ export declare type ExportProgress = (current: number, total: number) => void; /** The public y-protocols Awareness surface needed by a borrowed session. */ declare interface ExternalCollaborationAwareness extends AwarenessLike { clientID: number; getLocalState: () => Record | null; setLocalState: (state: Record | null) => void; off: (event: string, callback: () => void) => void; } /** * Host-owned Yjs resources. The host creates, connects and destroys them. * Keep this object and its resources stable for a session; report connection * changes through subscribe instead of replacing the collaboration config. */ declare interface ExternalCollaborationSession { readonly doc: Doc; /** Awareness must belong to doc. One viewer publishes slide presence at a time. */ readonly awareness: ExternalCollaborationAwareness; getSnapshot: () => ExternalCollaborationSnapshot; /** Subscribe to status or synced changes; return an unsubscribe function. */ subscribe: (listener: () => void) => () => void; } /** Connection state reported by the host, independent of the viewer lifetime. */ declare interface ExternalCollaborationSnapshot { status: ConnectionStatus; /** * The host has loaded the authoritative document and permits local edits. * Keep true while offline to allow ordinary Yjs offline edits, or set false * to suspend writes until a fresh sync. The viewer never infers this from * `status` and never opens it after a timeout. */ synced: boolean; } declare type FeedbackSoundScheme = 'modern' | 'classic'; declare type FillInput = { type: 'solid'; color: string; opacity?: number; /** * A theme colour to use instead of a plain hex. When set, the shape * saves as `` (e.g. `{ scheme: 'accent1', lumMod: 0.8 }` * for "Accent 1, Lighter 80%") so it keeps following the theme after a * later theme change; `color` still supplies the immediate resolved * hex for renderers that read it directly. */ themeColorRef?: PptxThemeColorRef; } | { type: 'gradient'; /** * Gradient direction in the OOXML `a:lin/@ang` convention: degrees * clockwise from the positive x-axis, pointing from the first stop * towards the last (`0` = left to right, `90` = top to bottom). This is * what lands in `ShapeStyle.fillGradientAngle` and what is written back * to the file, NOT a CSS `linear-gradient()` angle. */ angle?: number; gradientType?: 'linear' | 'radial'; stops: Array<{ color: string; position: number; opacity?: number; }>; } | { type: 'pattern'; preset: string; foreground?: string; background?: string; } | { type: 'image'; url: string; mode?: 'stretch' | 'tile'; } | { type: 'none'; }; /** Identifies a single match of the find query at segment-level precision. */ export declare interface FindResult { /** Zero-based index of the slide in the slides array. */ slideIndex: number; /** Id of the element that contains the match. */ elementId: string; /** Zero-based index of the text segment within the element's `textSegments`. */ segmentIndex: number; /** Character offset of the match start within the segment text. */ startOffset: number; /** Number of characters matched (equals `query.length`). */ length: number; } /** What the "Embed fonts in the file" toggle should look like and do. */ declare interface FontEmbeddingDescriptor { /** Distinct typeface names the loaded deck currently embeds. */ embeddedFamilies: string[]; /** * Whether the toggle accepts input. False when the deck embeds nothing, * because turning it on could not produce an embedded font. */ interactive: boolean; /** * The position the toggle must START in so that it describes the file that * would be written right now. A deck that arrived with embedded fonts keeps * them on save, so the switch has to read "on" from the outset; the previous * hardcoded `false` said the opposite of what save actually did. */ initialEnabled: boolean; /** Present only when `interactive` is false. */ disabledReasonKey?: string; } /** * Format a millisecond duration as `M:SS` (minutes are not zero-padded, seconds * are). Matches the React `RehearseTimingsHud`/`RehearseTimingsSummary` * `formatMs` helper. */ export declare function formatRehearseMs(ms: number): string; /** One layer (outgoing or incoming) rendered as N independent fragments. */ declare interface FragmentedLayer { /** Name of the shared `@keyframes` block every fragment in this layer runs. */ keyframesName: string; /** Per-fragment `animation-duration`, in ms. */ durationMs: number; /** Per-fragment `animation-timing-function`. */ easing: string; fragments: readonly TransitionFragment[]; } export declare const FragmentedTransitionLayer: typeof __VLS_export_3; /** The two click-to-place drawing tools. */ declare type FreeformToolKind = 'freeformShape' | 'curve'; /** Generate a stable, collision-resistant comment id. */ export declare function generateCommentId(): string; /** * Geometry types: adjustment handles, custom geometry points, segments, * paths, and custom path properties. * * @module pptx-types/geometry */ /** * Defines an adjustment handle position for a shape geometry. * * Adjustment handles allow users to interactively reshape preset shapes * (e.g. rounding a rectangle corner or adjusting arrow head width). * * @example * ```ts * const handle: GeometryAdjustmentHandle = { * guideName: "adj", * xFraction: 0.25, * minValue: 0, * maxValue: 50000, * }; * // => satisfies GeometryAdjustmentHandle * ``` */ declare interface GeometryAdjustmentHandle { /** Name of the adjustment guide this handle controls (e.g. "adj", "adj1"). */ guideName: string; /** X position as a fraction of shape width (0..1), or undefined if the handle only moves vertically. */ xFraction?: number; /** Y position as a fraction of shape height (0..1), or undefined if the handle only moves horizontally. */ yFraction?: number; /** Minimum allowed value for the adjustment guide. */ minValue?: number; /** Maximum allowed value for the adjustment guide. */ maxValue?: number; } /** * Resolve a p15 cinematic transition to its CSS `animation` descriptors, or * `undefined` when the type is not a cinematic transition (so the caller can * fall through to the classic 2-D / p14 resolvers). */ export declare function getCinematicTransitionAnimations(type: PptxTransitionType, durationMs: number, direction: string | undefined, orient?: string | undefined): SlideTransitionAnimations | undefined; /** * Return CSS animation descriptors for p14 transition types. Returns * `undefined` when the type is not a p14 transition. */ export declare function getP14TransitionAnimations(type: PptxTransitionType, durationMs: number, direction: string | undefined, orient?: string | undefined, pattern?: string | undefined): SlideTransitionAnimations | undefined; /** * Map a {@link PptxTransitionType} (+ duration/direction/orient/spokes) to the * concrete CSS `animation` descriptors for the outgoing and incoming layers. * * Unknown types fall back to a symmetrical cross-fade. */ export declare function getSlideTransitionAnimations(type: PptxTransitionType, durationMs: number, direction: string | undefined, orient?: string | undefined, spokes?: number | undefined, pattern?: string | undefined): SlideTransitionAnimations; /** GIF-only tuning, in addition to the shared `MediaExportOptions`. */ export declare interface GifExportOptions extends MediaExportOptions { /** * Longest allowed frame side in pixels after capture; a captured canvas * larger than this is downscaled before quantisation (GIF encoding cost * grows with pixel count). Defaults to the shared * `GIF_POST_CAPTURE_MAX_SIDE` (see `resolveExportCaptureDecision`'s * `postCaptureMaxSide` for the `'gif'` format). */ maxSide?: number; } /** A single animated-GIF frame: raw RGBA pixels plus its dimensions. */ declare interface GifFrame { imageData: ImageData; width: number; height: number; /** * Optional per-frame delay in **centiseconds** (1 cs = 10 ms). When set it * overrides the encoder-level delay for this frame only, which is how * per-slide durations from {@link planGifFrames} flow into the encoder. */ delayCs?: number; } declare interface GroupOptions extends Partial {} /** * A group container that holds child elements. * * Children inherit the group’s transform, so moving/resizing the group * affects all children proportionally. * * @example * ```ts * const group: GroupPptxElement = { * type: "group", * id: "grp_1", x: 0, y: 0, width: 960, height: 540, * children: [textEl, shapeEl], * }; * // => satisfies GroupPptxElement * ``` */ declare interface GroupPptxElement extends PptxElementBase { type: 'group'; /** Child elements contained within this group. */ children: PptxElement[]; /** Fill style extracted from the group's `p:grpSpPr`, used for `a:grpFill` inheritance. */ groupFill?: ShapeStyle; /** * The SAME `p:grpSpPr` extraction as {@link groupFill}, kept whenever the * group carries a `p:grpSpPr` at all, regardless of whether it resolved to * a paintable fill. * * `groupFill` is `undefined` unless the group has a real fill, because * `getGroupChildParentFill`/`groupChildInheritedFill` (the `a:grpFill` * inheritance chain) must keep chaining through an ancestor's fill when * THIS group has none of its own. A group whose `p:grpSpPr` authors only * `a:effectLst` (shadow/glow/soft-edge/reflection, no fill) needs those * effects to still reach the renderer, so they are kept here under a name * that carries no fill-inheritance meaning. Currently only reflection is * read from it (`getComputedEffectStyle`); the rest of `a:effectLst` on a * group remains unsupported. */ groupEffectStyle?: ShapeStyle; /** * Exact EMU the group's own `a:chOff`/`a:chExt` (the coordinate space its * CHILDREN are authored in) were parsed from, alongside {@link * PptxElementBase.xEmu} etc for the group's own placement in its PARENT's * space. `undefined` when the source carried no usable `a:chOff`/`a:chExt` * (an SDK-created group, or one whose `a:xfrm` had no child-space data). * * Used by `group-xfrm-preservation.ts`'s `hasCapturedChildSpace` to decide * whether this group's original `a:chOff`/`a:chExt` can be re-emitted * verbatim (always true once captured, regardless of whether anything in * the subtree has moved or resized - only its DIRECT children's * `a:off`/`a:ext` are recomputed, via `invertChildIntoGroupSpace`, when * something changed), instead of the normalized `chOff 0,0` / `chExt == * ext` space the writer falls back to when this is `undefined` (or * degenerate). See `group-shape-geometry.ts`'s module doc for why a group * needs two coordinate systems at all. */ chOffXEmu?: number; /** See {@link chOffXEmu}. */ chOffYEmu?: number; /** See {@link chOffXEmu}. */ chExtWidthEmu?: number; /** See {@link chOffXEmu}. */ chExtHeightEmu?: number; } /** Group the catalog for display (preserves the label order). */ export declare function groupShortcutCatalog(catalog?: readonly ShortcutDefinition[]): ShortcutCatalogGroup[]; /** A single alignment guide, positioned in authored slide pixels. */ declare interface Guide { id: string; axis: 'h' | 'v'; position: number; } /** * Pure handout layout calculations, shared by every binding's print path. * * Handles distributing slides across pages, computing grid dimensions, and * positioning cells within A4 page space. No DOM/framework dependency: callers * render the resulting rectangles however their view layer prefers. */ /** Supported slides-per-page values. */ declare type HandoutSlidesPerPage = 1 | 2 | 3 | 4 | 6 | 9; export declare const HIGHLIGHTER_OPACITY = 0.4; export declare const HIGHLIGHTER_WIDTH = 14; declare interface ImageOptions extends Partial { altText?: string; cropLeft?: number; cropTop?: number; cropRight?: number; cropBottom?: number; opacity?: number; } /** * An image element from an OOXML `` node with `type: "image"`. * * @example * ```ts * const img: ImagePptxElement = { * type: "image", * id: "img_1", x: 0, y: 0, width: 960, height: 540, * imagePath: "ppt/media/image1.png", * altText: "Background scenery", * }; * // => satisfies ImagePptxElement * ``` */ declare interface ImagePptxElement extends PptxElementBase, PptxShapeProperties, PptxCustomPathProperties, PptxImageProperties, PptxAccessibilityProperties, PptxPictureNonVisualProperties { type: 'image'; } declare type ImageResolutionPreset = 'highFidelity' | 'ppi330' | 'ppi220' | 'ppi150' | 'ppi96'; /** Resolve the injected selection context, if any (read-only viewers omit it). */ export declare function injectTableSelection(): TableSelectionContext | undefined; /** A 2D point in stage-local coordinates. */ declare interface InkPoint { x: number; y: number; /** * Pointer pressure at this point, from `PointerEvent.pressure` (0..1). * Optional: a binding that has not wired pressure capture simply omits * it, and {@link strokeToInkElement} falls back to * {@link DEFAULT_POINTER_PRESSURE}, the constant value mice and other * non-pressure-aware devices report, which reads as "no real pressure * data". */ pressure?: number; /** * Pen-tilt lean, in degrees, from `PointerEvent.tiltX`/`tiltY` on * supporting hardware (a mouse, or a stylus with no tilt sensor, reports a * constant 0). Optional and always captured as a pair: a binding that has * not wired tilt capture simply omits both, and {@link strokeToInkElement} * treats a constant `(0, 0)` reading the same way it treats a constant * pressure, i.e. as "no real tilt data" rather than authoring a channel * for it. */ tiltX?: number; tiltY?: number; } /** * A freehand ink / drawing stroke captured with a stylus or mouse. * * Ink strokes are stored as SVG path data strings. Each path may * have independent colour, width, and opacity. */ declare interface InkPptxElement extends PptxElementBase { type: 'ink'; /** SVG path data for ink strokes. */ inkPaths: string[]; /** Per-path stroke colours. */ inkColors?: string[]; /** Per-path stroke widths. */ inkWidths?: number[]; /** Per-path opacities (0-1). */ inkOpacities?: number[]; /** Drawing tool used: pen, highlighter, or eraser. */ inkTool?: 'pen' | 'highlighter' | 'eraser'; /** * Per-path arrays of per-point pressure values (0-1). * * Each entry corresponds to the path at the same index in `inkPaths`. * Each inner array contains one pressure value per sampled point along * the stroke. When present, the renderer uses these values to produce * variable-width strokes that reflect stylus/pen pressure. */ inkPointPressures?: number[][]; /** * Per-path arrays of per-point pen-tilt lean direction (degrees, straight * from `PointerEvent.tiltX` on supporting hardware). * * Each entry corresponds to the path at the same index in `inkPaths`, and * is paired positionally with {@link inkPointTiltY}. Present only when at * least one point in the stroke reported a genuinely non-zero tilt: a * device that never reports tilt (a mouse, or a stylus with no tilt * sensor) leaves both arrays absent, the same way `inkPointPressures` is * omitted when pressure never varies. When present, the renderer converts * the raw `(tiltX, tiltY)` vector into a lean angle + magnitude (see * `pptx-viewer-shared`'s `tiltChannelsFromVectors`) and widens the stroke * perpendicular to the lean direction, approximating a chisel-tip * calligraphy nib. */ inkPointTiltX?: number[][]; /** Per-path, per-point pen-tilt lean direction (degrees), paired with {@link inkPointTiltX}. */ inkPointTiltY?: number[][]; /** Unrecognised graphicFrame extLst extensions, captured verbatim for round-trip. */ extensionXml?: PptxGraphicFrameExtension[]; } /** Project a node's on-screen rect into container-relative pixels for overlay. */ export declare function inlineEditorRect(nodeRect: InlineEditRect, containerRect: InlineEditRect): InlineEditRect; /** A minimal rectangle (DOMRect-compatible) used for overlay positioning. */ declare interface InlineEditRect { left: number; top: number; width: number; height: number; } declare interface InlineListController { read(): InlineListReadResult; format(snapshot: InlineTextEditSnapshot): InlineListReadResult; readSelection(selection?: Selection | null): InlineListSelectionResult; refresh(): InlineListReadResult; dispose(): void; } declare type InlineListReadResult = { kind: 'supported'; snapshot: InlineTextEditSnapshot; paragraphs: RenderParagraph[]; } | { kind: 'unsupported'; reason: string; text: string; }; declare type InlineListSelectionResult = { kind: 'supported'; snapshot: InlineTextEditSnapshot; selection: InlineTextSelection | null; bodyRange?: { start: number; end: number; }; } | { kind: 'unsupported'; reason: string; }; /** Current editor payload. Missing segments explicitly denotes plain-text fallback. */ declare interface InlineTextEditSnapshot { elementId: string; text: string; textSegments?: TextSegment[]; } /** Describes which segments (and offsets within them) are selected. */ declare interface InlineTextSelection { startSegIdx: number; startOffset: number; endSegIdx: number; endOffset: number; } /** * Dropdown ids for the insert-chart menu. Distinct from `PptxChartType` * because PowerPoint offers Column (vertical) and Bar (horizontal) as two * entries over the same underlying `'bar'` chart type, and because `'pareto'` * has no `PptxChartType` of its own: it is a dropdown entry that resolves to * `type: 'histogram'` (see docs/guide/limitations.md's ChartEx row) with a * frequency-plus-cumulative-percentage default shape. The other six ChartEx * ids (`histogram` through `regionMap`) map one-to-one onto their chart type. */ declare type InsertChartKind = 'column' | 'bar' | 'line' | 'pie' | 'doughnut' | 'area' | 'scatter' | 'histogram' | 'pareto' | 'funnel' | 'treemap' | 'sunburst' | 'boxWhisker' | 'regionMap'; /** No-animation sentinel — used for `none`/`cut` (instant slide swap). */ export declare const INSTANT: SlideTransitionAnimations; declare interface IPptxHandlerRuntime { /** * Release all resources held by this runtime (Blob URLs, caches, ZIP). * After calling, the runtime cannot be used further. */ dispose(): void; /** * Revoke all Blob URLs created during image loading. */ revokeBlobUrls(): void; getCompatibilityWarnings(): PptxCompatibilityWarning[]; getLayoutOptions(): PptxLayoutOption[]; getLayoutPreview(layoutPath: string): Promise; getLayoutPreviews(layoutPaths?: readonly string[]): Promise; createXmlBuilder(data: PptxData): PptxXmlBuilder; Builder(data: PptxData): PptxXmlBuilder; setTemplateBackground(path: string, backgroundColor: string | undefined): void; setPresentationTheme(themePath: string, applyToAllMasters?: boolean): Promise; getTemplateBackgroundColor(path: string): string | undefined; updateThemeColorScheme(colorScheme: PptxThemeColorScheme): Promise; updateThemeFontScheme(fontScheme: PptxThemeFontScheme): Promise; updateThemeName(name: string): Promise; /** Resolve a `` node against the loaded theme (see PptxHandlerRuntimeStyleMatrixResolve). */ resolveStyleMatrixReferences(styleXml: XmlObject): ResolvedStyleMatrix; applyTheme(colorScheme: PptxThemeColorScheme, fontScheme: PptxThemeFontScheme, themeName?: string): Promise; load(data: ArrayBuffer, options?: PptxHandlerLoadOptions): Promise; getChartDataForGraphicFrame(slidePath: string, graphicFrame: XmlObject | undefined): Promise; getSmartArtDataForGraphicFrame(slidePath: string, graphicFrame: XmlObject | undefined): Promise; getImageData(imagePath: string): Promise; /** * Extract a media file from the PPTX archive as an ArrayBuffer. * Returns undefined if the file is not found. */ getMediaArrayBuffer(mediaPath: string): Promise; save(slides: PptxSlide[], options?: PptxHandlerSaveOptions): Promise; exportSlides(slides: PptxSlide[], options: PptxExportOptions): Promise>; /** * Get the available slide layouts for a specific slide, based on the * slide's master. Scans the slide master's relationships to find all * layouts that belong to it. * * @param slideIndex - Zero-based slide index. * @param slides - Current slides array. * @returns Array of layout options belonging to the same slide master. */ getAvailableLayoutsForSlide(slideIndex: number, slides: PptxSlide[]): Promise; /** * Resolve the editable template (master + layout) elements a slide * inherits, each carrying a `master-` / `layout-` prefixed id. Excludes * placeholders; returns only decorative shapes/pictures/graphic frames. * * @param slideId - The slide's archive path (`PptxSlide.id`). */ getTemplateElementsForSlide(slideId: string): Promise; /** * Scan the loaded PPTX archive for all theme parts. */ getAvailableThemes(): Promise>; /** * Apply a different layout to an existing slide by updating the slide's * relationship to point to the new layout and re-parsing layout * placeholders / background. * * @param slideIndex - Zero-based slide index. * @param layoutPath - Archive path of the target layout * (e.g. `ppt/slideLayouts/slideLayout2.xml`). * @param slides - Current slides array. * @returns The updated slide with new layout path, name, and background. */ applyLayoutToSlide(slideIndex: number, layoutPath: string, slides: PptxSlide[]): Promise; } /** * Abstract factory contract for creating {@link IPptxHandlerRuntime} * instances. * * Implement this interface to supply a custom runtime (e.g. a * WASM-backed or test-double runtime) to {@link PptxHandlerCore}. */ declare interface IPptxHandlerRuntimeFactory { /** Instantiate and return a new runtime implementation. */ createRuntime(): IPptxHandlerRuntime; } /** * Fluent interface for navigating and mutating a {@link PptxData} structure. * Provides method-chaining access to slides, elements, and notes. */ declare interface IPptxXmlBuilder { /** Navigate to a slide by zero-based index (Pascal-case alias). */ Slides(index: number): PptxSlideBuilder; /** Navigate to a slide by zero-based index. */ slide(index: number): PptxSlideBuilder; /** Navigate to a slide by zero-based index (plural alias). */ slides(index: number): PptxSlideBuilder; /** Return the underlying presentation data. */ project(): PptxData; } /** * Whether a viewport should use the mobile layout: a narrow viewport, OR a * short touch viewport below the tablet width (a landscape phone, which is wide * enough to look like a tablet but far too short for the desktop ribbon). * * @pure: no side effects, fully testable without a DOM. */ export declare function isMobileViewport(width: number, height: number, isTouch: boolean): boolean; export declare interface LaserPosition { x: number; y: number; } /** A `{ path, name }` layout option for the New-Slide dropdown. */ declare interface LayoutOption { path: string; name: string; } /** Interim geometry for an element mid-gesture. All fields optional. */ declare interface LiveGeometryPatch { x?: number; y?: number; width?: number; height?: number; rotation?: number; } /** The element's pre-edit rich text, used to remap the interim plain text. */ declare interface LiveTextSource { textSegments?: TextSegment[]; textStyle?: TextStyle; } declare type LocalTextEdit = LocalTextReplacement | TextSessionCorrespondence; /** Browser edit range mapped to the editor's pre-input encoded coordinates. */ declare interface LocalTextReplacement { from: number; to: number; } /** * Active tab within the master view sidebar. * * @example * ```ts * const tab: MasterViewTab = "slides"; * // => "slides" — one of: "slides" | "notes" | "handout" * ``` */ declare type MasterViewTab = 'slides' | 'notes' | 'handout'; /** Which part the master view is currently pointed at. */ declare interface MasterViewTarget { tab: MasterViewTab; masterIndex: number; /** `null` selects the master itself rather than one of its layouts. */ layoutIndex: number | null; } /** Result of matching a keyboard event against the catalog. */ export declare interface MatchedShortcut { /** The dispatched action, or `null` when the event matches nothing. */ action: ShortcutActionName | null; /** Nudge delta (only set when `action === 'nudge'`). */ dx?: number; /** Nudge delta (only set when `action === 'nudge'`). */ dy?: number; } /** * Material preset type tokens from OOXML `a:sp3d/@prstMaterial`. * * @example * ```ts * const mat: MaterialPresetType = "plastic"; * // => "plastic" — one of: "matte" | "warmMatte" | "plastic" | "metal" | "dkEdge" | … * ``` */ declare type MaterialPresetType = 'matte' | 'warmMatte' | 'plastic' | 'metal' | 'dkEdge' | 'softEdge' | 'flat' | 'softmetal' | 'clear' | 'powder' | 'translucentPowder' | 'legacyMatte' | 'legacyPlastic' | 'legacyMetal' | 'legacyWireframe'; /** * A named bookmark within a media clip timeline. * * @example * ```ts * const bm: MediaBookmark = { * id: "bm1", * time: 12.5, * label: "Intro ends", * }; * // => satisfies MediaBookmark * ``` */ declare interface MediaBookmark { id: string; /** Position in seconds from the start of the clip. */ time: number; /** User-visible label for this bookmark. */ label: string; } /** * A closed-caption / subtitle track associated with a media element. * * @example * ```ts * const track: MediaCaptionTrack = { * id: "t1", * label: "English", * language: "en", * kind: "subtitles", * isDefault: true, * }; * // => satisfies MediaCaptionTrack * ``` */ declare interface MediaCaptionTrack { /** Unique ID for this track. */ id: string; /** Human-readable label (e.g. "English", "Spanish"). */ label: string; /** BCP-47 language code (e.g. "en", "es"). */ language: string; /** Track kind: subtitles, captions, or descriptions. */ kind: 'subtitles' | 'captions' | 'descriptions'; /** Data URL or path to the VTT/SRT content within the PPTX archive. */ src?: string; /** Inline VTT content (for embedded captions). */ content?: string; /** Whether this track is the default/active one. */ isDefault?: boolean; } /** Options accepted by both `exportGif` and `exportWebm`. */ export declare interface MediaExportOptions { /** Default display time per slide, in milliseconds. */ slideDurationMs?: number; /** Per-slide duration overrides in ms (index maps to slide index). */ slideTimingsMs?: number[]; /** Capture-phase progress callback: `(currentSlide, totalSlides)`. */ onProgress?: MediaExportProgress; /** Abort the export early. */ signal?: AbortSignal; } /** Per-slide progress callback: `(currentSlideIndex, totalSlides)`. */ export declare type MediaExportProgress = (current: number, total: number) => void; /** * Runtime-extracted metadata about a media clip (populated from HTMLMediaElement). * * @example * ```ts * const meta: MediaMetadata = { * duration: 120.5, * videoWidth: 1920, * videoHeight: 1080, * codecInfo: "video/mp4; codecs=\"avc1.640028\"", * }; * // => satisfies MediaMetadata * ``` */ declare interface MediaMetadata_2 { /** Duration in seconds. */ duration?: number; /** Video width in pixels (video only). */ videoWidth?: number; /** Video height in pixels (video only). */ videoHeight?: number; /** MIME type / codec string reported by the browser. */ codecInfo?: string; } declare interface MediaOptions extends Partial { autoPlay?: boolean; loop?: boolean; volume?: number; trimStartMs?: number; trimEndMs?: number; posterFrame?: string; } /** * An audio or video media element. * * Media elements reference files inside the PPTX archive * (`mediaPath`) and may include trim points, poster frames, and * playback settings for presentation mode. * * @example * ```ts * const video: MediaPptxElement = { * type: "media", * id: "vid_1", x: 50, y: 100, width: 640, height: 360, * mediaType: "video", * mediaPath: "ppt/media/media1.mp4", * autoPlay: true, * volume: 0.8, * }; * // => satisfies MediaPptxElement * ``` */ declare interface MediaPptxElement extends PptxElementBase { type: 'media'; mediaType?: PptxMediaType; mediaPath?: string; mediaData?: string; mediaMimeType?: string; mediaReferenceKind?: PptxMediaReferenceKind; mediaReferenceName?: string; /** Explicit DrawingML `audioFile/@contentType` value when present. */ mediaReferenceContentType?: string; audioCdStart?: PptxAudioCdPosition; audioCdEnd?: PptxAudioCdPosition; rawMediaReferenceXml?: XmlObject; /** Trim start in milliseconds (from p:cMediaNode p:cTn @st). */ trimStartMs?: number; /** Trim end in milliseconds (from p:cMediaNode p:cTn @end). */ trimEndMs?: number; /** Path to the poster/preview image inside the ZIP. */ posterFramePath?: string; /** Base64 data-URL for the poster frame image. */ posterFrameData?: string; /** Poster source crop from the left edge as a 0..1 fraction. */ cropLeft?: number; /** Poster source crop from the top edge as a 0..1 fraction. */ cropTop?: number; /** Poster source crop from the right edge as a 0..1 fraction. */ cropRight?: number; /** Poster source crop from the bottom edge as a 0..1 fraction. */ cropBottom?: number; /** Poster stretch-target inset from the left frame edge. */ fillRectLeft?: number; /** Poster stretch-target inset from the top frame edge. */ fillRectTop?: number; /** Poster stretch-target inset from the right frame edge. */ fillRectRight?: number; /** Poster stretch-target inset from the bottom frame edge. */ fillRectBottom?: number; /** Whether media should play full-screen during presentation. */ fullScreen?: boolean; /** Whether media should loop continuously. */ loop?: boolean; /** Fade-in duration in seconds. */ fadeInDuration?: number; /** Fade-out duration in seconds. */ fadeOutDuration?: number; /** Playback volume (0 to 1). */ volume?: number; /** Whether media auto-plays on slide entry. */ autoPlay?: boolean; /** Whether audio continues playing across slide transitions (presentation mode). */ playAcrossSlides?: boolean; /** Hide the element when media is not actively playing. */ hideWhenNotPlaying?: boolean; /** Named time bookmarks within the clip. */ bookmarks?: MediaBookmark[]; /** Playback speed multiplier (1 = normal, 2 = double, 0.5 = half). */ playbackSpeed?: number; /** Runtime-extracted metadata (duration, resolution, codec). */ metadata?: MediaMetadata_2; /** Closed caption / subtitle tracks. */ captionTracks?: MediaCaptionTrack[]; /** Whether the media source is missing/broken (file not found in archive). */ mediaMissing?: boolean; /** * Whether the media is linked (external `r:link`) rather than embedded * (`r:embed`). Defaults to embedded when undefined. */ isLinked?: boolean; /** * Accessibility description. Read from `p:nvGraphicFramePr/p:cNvPr/@descr` * for the `p:graphicFrame`-shaped (SDK-created) media form, or from * `p:nvPicPr/p:cNvPr/@descr` for the `p:pic`-shaped media form (real * PowerPoint's usual authoring shape for a video/audio placeholder); see * `PptxHandlerRuntimePictureParsing.ts`. */ altText?: string; /** Accessibility title, from the same `@title` attribute on whichever `p:cNvPr` the media form uses. Same scope note as {@link altText}. */ title?: string; /** Unrecognised graphicFrame extLst extensions, captured verbatim for round-trip. */ extensionXml?: PptxGraphicFrameExtension[]; } /** * Factory for a `MediaRecorder` over a canvas capture stream. Injectable so the * WebM path can be exercised in happy-dom (which ships no `MediaRecorder`). */ export declare type MediaRecorderFactory = (canvas: HTMLCanvasElement, fps: number, options: { mimeType: string; videoBitsPerSecond: number; }) => MediaRecorder; declare type MergeCropController = MergeShapesController & PictureCropController; /** Supported merge shape operations (matching PowerPoint's Merge Shapes menu). */ declare type MergeShapeOperation = 'union' | 'intersect' | 'subtract' | 'fragment' | 'combine'; /** The right-click command id for each operation. */ declare type MergeShapesCommandId = 'merge-union' | 'merge-combine' | 'merge-fragment' | 'merge-intersect' | 'merge-subtract'; /** Merge Shapes: the ribbon dropdown and the context-menu entries. */ declare interface MergeShapesController { /** Editable deck and two or more mergeable shapes selected. */ canMerge: ComputedRef; /** Run `op` over the selection (in selection order) as one undo step. */ merge: (op: MergeShapeOperation) => void; } /** Mobile breakpoint: below this width is considered mobile. */ export declare const MOBILE_BREAKPOINT = 768; /** * Max viewport height (px) at which a *touch* device is treated as mobile * regardless of width. Catches landscape phones (e.g. 915x412), which are wide * enough to fall in the "tablet" width band but far too short for the desktop * ribbon + side panels, so they need the mobile chrome. Tablets in landscape * are taller (~760px+) so they stay on the desktop layout. */ export declare const MOBILE_LANDSCAPE_MAX_HEIGHT = 500; /** Which mobile bottom-bar tab is highlighted (null = none open). */ export declare type MobileActiveSheet = MobileSheetKind | null; export declare type MobileSheetKind = 'slides' | 'format' | 'comments' | 'notes'; /** * A 3D model object embedded via `p16:model3D` inside an * `mc:AlternateContent` block (PowerPoint 365+). * * The element carries the path to the `.glb`/`.gltf` binary inside * the ZIP and a poster/fallback image for rendering in viewers that * do not support interactive 3D. */ declare interface Model3DPptxElement extends PptxElementBase, PptxImageProperties { type: 'model3d'; /** Path to the 3D model file inside the ZIP. */ modelPath?: string; /** Base64 data URL of the 3D model binary. */ modelData?: string; /** MIME type of the model (e.g. "model/gltf-binary"). */ modelMimeType?: string; /** Poster/preview image shown when 3D rendering is unavailable. */ posterImage?: string; /** Unrecognised graphicFrame extLst extensions, captured verbatim for round-trip. */ extensionXml?: PptxGraphicFrameExtension[]; } /** A matched pair whose two halves are both painted by the overlay. */ declare interface MorphCrossfadeGroup { /** The outgoing (ghost) half, rendered in the OUTGOING slide's context. */ outgoing: PptxElement; /** The incoming half, rendered in the INCOMING slide's context. */ incoming: PptxElement; /** * The dissolve to run on the outgoing half's own WRAPPER, not on the element. * * A pair that dissolves where it stands never moves, so its journey keyframes * are an identity transform and are dropped; what is left is the fade. Put * that fade on the element and the element becomes its own compositing layer, * whose raster the browser snaps to whole device pixels: the wording is * painted up to a third of a pixel from where the live stage paints it, so it * visibly twitches as the transition starts and again as it ends. Measured on * the wheel deck at four show sizes, moving the fade onto the slide-sized * wrapper takes the arriving half from 0.22-0.31px off to under 0.02px - a * mean pixel difference of 0.01/255 against the settled slide. * * Undefined when the pair MOVES: it needs its journey keyframes on the * element, and a shape that is travelling cannot be seen to snap. */ outgoingAnimation?: string; /** The arriving half's dissolve. @see MorphCrossfadeGroup.outgoingAnimation */ incomingAnimation?: string; } /** One entry of {@link useMorphTransitionOverlay}'s `morphCrossfadeGroups`. */ export declare type MorphCrossfadeGroupView = ReturnType['morphCrossfadeGroups']['value'][number]; export declare const MorphExtraLayers: typeof __VLS_export_2; /** Everything needed to play one morph transition. */ declare interface MorphTransitionPlan { /** All `@keyframes` blocks, to inject as a single stylesheet. */ keyframesCss: string; /** Incoming-slide element id -> CSS `animation` shorthand. */ incomingAnimations: Map; /** Outgoing-slide element id -> CSS `animation` shorthand. */ outgoingAnimations: Map; /** * Incoming-slide element id -> CSS `animation` shorthand for the `` * INSIDE that element, never for the element's own container. * * A picture's source crop (`a:srcRect`, which is what PowerPoint's "Scale * Height"/"Scale Width" writes) is painted by transforming the img within * its frame, and the frame itself is usually identical on both slides - so * this is a separate channel rather than another entry in * {@link MorphTransitionPlan.incomingAnimations}, which would collide on the * same element id. {@link buildMorphScopedCss} emits it as a descendant * rule; a binding that applies animations as inline props instead must * target the img itself (issue #148). */ incomingImageAnimations: Map; /** Outgoing (ghost) counterpart of {@link MorphTransitionPlan.incomingImageAnimations}. */ outgoingImageAnimations: Map; /** * Incoming-slide element id -> CSS `animation` shorthand for the copy the * overlay paints, above every ghost. * * These are the arriving shapes a ghost would otherwise hide for the whole * transition (see {@link MorphTransitionPlan.overlayIncomingElements}). Their * entry in {@link MorphTransitionPlan.incomingAnimations} has been replaced * by one that holds them invisible, so the stage copy stays out of the way * and only this one is seen. */ overlayIncomingAnimations: Map; /** * The incoming-slide elements to paint in the overlay ON TOP of * {@link MorphTransitionPlan.outgoingElements}, in document order. * * The overlay is one flat layer above the live stage, which is only faithful * while every ghost really does belong on top of everything the stage draws. * A shape arriving INSIDE a persisting one does not: the wheel deck's centre * disc is unchanged between slides, so its ghost is opaque for the whole * morph, and the title and body dissolving in within it were invisible until * the overlay came down (issue #146). Painting those here restores the order * PowerPoint composites in. * * Usually empty. A binding renders these with the INCOMING slide as their * context, applying {@link MorphTransitionPlan.overlayIncomingAnimations}. * * A lifted half that is one end of a cross-dissolve is NOT here: it moves * into {@link MorphTransitionPlan.crossfadeGroups} so it can be composited * with its own ghost. */ overlayIncomingElements: PptxElement[]; /** * Pairs the overlay paints BOTH halves of, to be rendered as one isolated * group blending additively (see `morph-crossfade-group`). * * Their elements are deliberately absent from * {@link MorphTransitionPlan.outgoingElements} and * {@link MorphTransitionPlan.overlayIncomingElements}: a binding that renders * the groups paints each half exactly once, and one that ignored them would * drop the pair rather than paint it twice. * * A pair that dissolves where it stands also has its dissolve moved OFF the * two elements and onto {@link MorphCrossfadeGroup.outgoingAnimation} / * {@link MorphCrossfadeGroup.incomingAnimation}, for the binding to put on * the wrapper it paints each half in; the elements are then absent from * `outgoingAnimations` / `overlayIncomingAnimations` too, so no scoped rule * animates them. One that MOVES keeps its animations where they were. * * Painted above {@link MorphTransitionPlan.overlayIncomingElements}, in the * incoming slide's document order. */ crossfadeGroups: MorphCrossfadeGroup[]; /** * The outgoing slide's elements, in document order, for the binding to * render in its transition overlay for the duration of the morph. Most carry * an entry in {@link MorphTransitionPlan.outgoingAnimations}: they either * fade out in place (no counterpart) or glide onto a counterpart, dissolving * into it when the appearance changed. * * A ghost standing in for an INERT pair deliberately has no entry there and * is painted statically. Its keyframes would run from itself to itself, and * a running animation would put it on its own compositing layer, whose * raster the browser snaps to whole device pixels - visibly shifting a shape * that is not supposed to move at all (issue #161). * * This is a SUBSET of the outgoing slide: a shape the live stage already * draws identically is left out, because the overlay is opaque above it and * would hide the incoming slide's own arrivals. See `resolveMorphGhostIds`. */ outgoingElements: PptxElement[]; /** Animation duration in ms, echoed for convenience. */ durationMs: number; } /** * smartart-inline-edit (Vue): reactive state + node-id mapping for on-canvas * SmartArt node text editing. Kept out of the SFC so the component stays thin * (CLAUDE.md <= 300 LOC) and the mapping is unit-testable. * * Pure rect projection and the no-op-commit guard live in the framework-agnostic * `pptx-viewer-shared` (`computeInlineEditorRect`, `shouldCommitSmartArtNodeText`) * and are reused here rather than reimplemented. This module adds only the * Vue-reactive edit state and the rendered-node -> source-node-id mapping. */ /** * Pair each rendered fallback-layout node with its source node id by matching * `flattenNodes` order: the per-family layout functions iterate the flattened * tree in the same order, so index `i` of the rendered list corresponds to * index `i` of the flattened source tree. */ export declare function nodeIdsInRenderOrder(roots: readonly PptxSmartArtNode[]): string[]; /** Slide pixels a Shift+arrow moves the selection (ten small steps). */ export declare const NUDGE_LARGE = 10; /** * Slide pixels an unmodified arrow key moves the selection. * * PowerPoint nudges by the smallest unit it can draw, and the ribbon's position * boxes are authored in the same slide-pixel space the renderer lays out in, so * one arrow press must equal one slide pixel or the numbers in the inspector * disagree with what the keyboard does. */ export declare const NUDGE_SMALL = 1; /** * Recognised OLE object application types derived from `progId` / `clsId`. * * Used to show type-specific icons and previews in the editor. */ declare type OleObjectType = 'excel' | 'word' | 'powerpoint' | 'pdf' | 'visio' | 'mathtype' | 'package' | 'unknown'; /** * An OLE (Object Linking and Embedding) object. * * OLE objects can be embedded Excel sheets, Word documents, PDFs, Visio * diagrams, MathType equations, or generic "packages". They carry a * preview image for display and optional binary data for extraction. * * @example * ```ts * const ole: OlePptxElement = { * type: "ole", * id: "ole_1", x: 100, y: 200, width: 400, height: 300, * oleObjectType: "excel", * oleProgId: "Excel.Sheet.12", * fileName: "budget.xlsx", * }; * // => satisfies OlePptxElement * ``` */ declare interface OlePptxElement extends PptxElementBase { type: 'ole'; oleTarget?: string; oleProgId?: string; oleName?: string; /** CLSID of the OLE object (from `@_classid`). */ oleClsId?: string; /** Detected application type (excel, word, pdf, etc.). */ oleObjectType?: OleObjectType; /** File extension for the embedded binary (e.g. "xlsx", "docx"). */ oleFileExtension?: string; /** Original file name when available. */ fileName?: string; /** Whether this is a linked (vs. embedded) object. */ isLinked?: boolean; /** External file path for linked OLE objects (TargetMode="External"). */ externalPath?: string; /** Data-URL or path for the OLE preview image. */ previewImage?: string; /** Decoded preview image as a data-URL. */ previewImageData?: string; /** Whether the OLE object is shown as an icon (`p:oleObj/@showAsIcon`). */ oleShowAsIcon?: boolean; /** Authored display width of the OLE object preview, in EMU (`@imgW`). */ oleImgW?: number; /** Authored display height of the OLE object preview, in EMU (`@imgH`). */ oleImgH?: number; /** * The recovered embedded payload as a data-URL (e.g. * `data:application/vnd...;base64,...`), suitable for download or * open-in-new-tab. For a generic "Package" OLE object this is the unwrapped * inner file; for a plain embedded file (e.g. `.xlsx`) it is that file * directly. Undefined when the embedding is missing or unreadable. * * Stored as a data-URL string to mirror how images store decoded bytes * ({@link ImagePptxElement.imageData}) and to stay serialization-safe. */ oleEmbeddedData?: string; /** Original file name of the embedded payload when recoverable. */ oleEmbeddedFileName?: string; /** MIME type of the embedded payload, derived from its extension/ProgID. */ oleEmbeddedMimeType?: string; /** Size of the embedded payload in bytes. */ oleEmbeddedByteSize?: number; /** * `p:link/@followColorScheme` (`ST_OleObjectFollowColorScheme`): whether a * LINKED OLE object's icon recolours to match the presentation theme. * Only meaningful when {@link isLinked} is `true`. ECMA-376 §19.3.1.28. */ oleFollowColorScheme?: 'none' | 'full' | 'textAndBackground'; /** * `p:link/@updateAutomatic` (`CT_OleObjectLink`, ECMA-376 §19.3.2.4): * whether a LINKED OLE object refreshes automatically from its source * (PowerPoint's Edit Links dialog "Automatic" vs. "Manual" radio buttons). * Only meaningful when {@link isLinked} is `true`. The schema default is * `false`; `undefined` means the source authored no explicit value. */ oleUpdateAutomatic?: boolean; /** * Set by the in-viewer OLE content editors (`ole-edit-api.ts`) whenever * `oleEmbeddedData` and/or `previewImageData` have been changed in memory * and still need to be written back into the saved package. Never * authored from a parsed file; purely an in-memory save signal, mirroring * `PptxSlide.isDirty`. The save writer clears it once the pending write * has been queued. */ oleContentDirty?: boolean; /** Accessibility description from `p:nvGraphicFramePr/p:cNvPr/@descr`. */ altText?: string; /** Accessibility title from `p:nvGraphicFramePr/p:cNvPr/@title`. */ title?: string; /** Unrecognised graphicFrame extLst extensions, captured verbatim for round-trip. */ extensionXml?: PptxGraphicFrameExtension[]; } declare type OpenDocumentsView = 'savedView' | 'normal' | 'outline' | 'slideSorter' | 'notes'; /** * Open a print window for a complete HTML document and trigger printing. * Returns `false` if the window was blocked (e.g. popup blocker). */ export declare type OpenPrintWindow = (htmlDocument: string) => boolean; /** * A File > Options page: the ten PowerPoint categories plus `ai`, the AI * assistant page a binding adds when the host configured an assistant. */ declare type OptionsPageId = ViewerOptionsTabId | 'ai'; declare type OptionsPrintColorMode = 'color' | 'grayscale' | 'blackAndWhite'; declare type OptionsPrintWhat = 'slides' | 'handouts' | 'notes' | 'outline'; /** * One section of an Options page, addressed as `.
`, for * example `general.personalize` or `advanced.print`. The full list is * `OPTIONS_SECTION_IDS` (derived from the schema at runtime). */ declare type OptionsSectionId = `${ViewerOptionsTabId}.${string}`; /** * One File > Options setting, addressed as `.`, for example * `general.userName` or `advanced.showGrid`. The union is derived from the * `ViewerOptions` model itself, so a typo is a compile error. */ declare type OptionsSettingId = { [G in ViewerOptionsGroupId]: `${G}.${PrimitiveKeys}`; }[ViewerOptionsGroupId]; /** Values a host forces onto settings. */ declare type OptionsSettingValues = Partial>; /** * Read-only digital-signature inspection composable for the Vue viewer. * * Digital signatures in OOXML packages live under `_xmlsignatures/`. The core * `PptxHandler` detects their presence at load time (it stores a * {@link import('pptx-viewer-core').SignatureDetectionResult} internally and * surfaces `hasDigitalSignatures` / `digitalSignatureCount` on `PptxData`), but * it does NOT expose the fully-parsed signatures. The host obtains the parsed * `ParsedSignature[]` itself, by reading each `_xmlsignatures/sig*.xml` part * and running the core `parseSignatureXml(...)` helper, then feeds the result * in here. This composable is purely presentational state derivation: it never * signs, strips, or mutates anything. * * Overall status precedence (worst-wins), mirroring how a signature panel * should warn the user: * invalid > expired / unknownCA > unverified > valid */ /** Overall package signature status derived from all individual signatures. */ export declare type OverallSignatureStatus = 'signed' | 'invalid' | 'unsigned'; /** Part 1: conveyor / doors / ferris / flash / flythrough / gallery / glitter / honeycomb / pan. */ export declare const P14_TRANSITION_KEYFRAMES = "\n/* ── Conveyor (translate X with staggered timing) ──────────────────── */\n@keyframes pptx-tr-conveyor-in-from-right {\n\tfrom { transform: translateX(100%) rotateY(-30deg); }\n\t60% { transform: translateX(20%) rotateY(-10deg); }\n\tto { transform: translateX(0) rotateY(0deg); }\n}\n@keyframes pptx-tr-conveyor-out-to-left {\n\tfrom { transform: translateX(0) rotateY(0deg); }\n\t40% { transform: translateX(-20%) rotateY(10deg); }\n\tto { transform: translateX(-100%) rotateY(30deg); }\n}\n@keyframes pptx-tr-conveyor-in-from-left {\n\tfrom { transform: translateX(-100%) rotateY(30deg); }\n\t60% { transform: translateX(-20%) rotateY(10deg); }\n\tto { transform: translateX(0) rotateY(0deg); }\n}\n@keyframes pptx-tr-conveyor-out-to-right {\n\tfrom { transform: translateX(0) rotateY(0deg); }\n\t40% { transform: translateX(20%) rotateY(-10deg); }\n\tto { transform: translateX(100%) rotateY(-30deg); }\n}\n\n/* ── Doors (clip-path from center split) ──────────────────────────────\n MEASURED via COM CreateVideo: PowerPoint's `dir=\"horz\"` names a\n HORIZONTAL split line (two panels stacked top/bottom, opening upward and\n downward), and `dir=\"vert\"` a VERTICAL split line (panels side by side,\n opening left and right) - the opposite of what \"clips left/right\" vs\n \"clips top/bottom\" would suggest at a glance. Keep the clip-path bodies\n matched to the MEASURED direction, not the intuitive one. */\n@keyframes pptx-tr-doors-horz {\n\tfrom { clip-path: inset(50% 0); }\n\tto { clip-path: inset(0 0); }\n}\n@keyframes pptx-tr-doors-vert {\n\tfrom { clip-path: inset(0 50%); }\n\tto { clip-path: inset(0 0); }\n}\n\n/* ── Ferris (rotate elements around center) ───────────────────────── */\n@keyframes pptx-tr-ferris-in-from-right {\n\tfrom { transform: translateX(80%) rotate(45deg) scale(0.6); opacity: 0; }\n\tto { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }\n}\n@keyframes pptx-tr-ferris-out-to-left {\n\tfrom { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }\n\tto { transform: translateX(-80%) rotate(-45deg) scale(0.6); opacity: 0; }\n}\n@keyframes pptx-tr-ferris-in-from-left {\n\tfrom { transform: translateX(-80%) rotate(-45deg) scale(0.6); opacity: 0; }\n\tto { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }\n}\n@keyframes pptx-tr-ferris-out-to-right {\n\tfrom { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }\n\tto { transform: translateX(80%) rotate(45deg) scale(0.6); opacity: 0; }\n}\n\n/* ── Flash (bright flash opacity burst) ──────────────────────────── */\n@keyframes pptx-tr-flash-white {\n\t0% { opacity: 1; }\n\t30% { opacity: 0; }\n\t50% { opacity: 0; }\n\t100% { opacity: 1; }\n}\n@keyframes pptx-tr-flash-in {\n\t0% { opacity: 0; }\n\t50% { opacity: 0; }\n\t70% { opacity: 1; }\n\t100% { opacity: 1; }\n}\n\n/* ── Flythrough (scale + translate Z-axis feel) ──────────────────── */\n@keyframes pptx-tr-flythrough-in {\n\tfrom { transform: scale(4) translateZ(200px); opacity: 0; filter: blur(8px); }\n\tto { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }\n}\n@keyframes pptx-tr-flythrough-out {\n\tfrom { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }\n\tto { transform: scale(0.1) translateZ(-200px); opacity: 0; filter: blur(8px); }\n}\n@keyframes pptx-tr-flythrough-reverse-in {\n\tfrom { transform: scale(0.1) translateZ(-200px); opacity: 0; filter: blur(8px); }\n\tto { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }\n}\n@keyframes pptx-tr-flythrough-reverse-out {\n\tfrom { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }\n\tto { transform: scale(4) translateZ(200px); opacity: 0; filter: blur(8px); }\n}\n\n/* ── Gallery (translate with perspective) ─────────────────────────── */\n@keyframes pptx-tr-gallery-in-from-right {\n\tfrom { transform: perspective(800px) translateX(100%) rotateY(-45deg); opacity: 0.5; }\n\tto { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }\n}\n@keyframes pptx-tr-gallery-out-to-left {\n\tfrom { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }\n\tto { transform: perspective(800px) translateX(-100%) rotateY(45deg); opacity: 0.5; }\n}\n@keyframes pptx-tr-gallery-in-from-left {\n\tfrom { transform: perspective(800px) translateX(-100%) rotateY(45deg); opacity: 0.5; }\n\tto { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }\n}\n@keyframes pptx-tr-gallery-out-to-right {\n\tfrom { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }\n\tto { transform: perspective(800px) translateX(100%) rotateY(-45deg); opacity: 0.5; }\n}\n\n/* ── Glitter (particle dissolve effect) ──────────────────────────── */\n@keyframes pptx-tr-glitter-in {\n\tfrom { opacity: 0; filter: brightness(1.5) contrast(1.3) blur(2px); }\n\t60% { opacity: 0.7; filter: brightness(1.2) contrast(1.1) blur(1px); }\n\tto { opacity: 1; filter: brightness(1) contrast(1) blur(0); }\n}\n\n/* ── Honeycomb (hexagonal reveal) ────────────────────────────────── */\n@keyframes pptx-tr-honeycomb-in {\n\tfrom {\n\t\tclip-path: polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%);\n\t\topacity: 0;\n\t}\n\tto {\n\t\tclip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);\n\t\topacity: 1;\n\t}\n}\n@keyframes pptx-tr-honeycomb-out {\n\tfrom { opacity: 1; }\n\tto { opacity: 0; filter: blur(2px); }\n}\n\n/* ── Pan (large-scale translate) ─────────────────────────────────── */\n@keyframes pptx-tr-pan-from-right {\n\tfrom { transform: translateX(100%); }\n\tto { transform: translateX(0); }\n}\n@keyframes pptx-tr-pan-to-left {\n\tfrom { transform: translateX(0); }\n\tto { transform: translateX(-100%); }\n}\n@keyframes pptx-tr-pan-from-left {\n\tfrom { transform: translateX(-100%); }\n\tto { transform: translateX(0); }\n}\n@keyframes pptx-tr-pan-to-right {\n\tfrom { transform: translateX(0); }\n\tto { transform: translateX(100%); }\n}\n@keyframes pptx-tr-pan-from-bottom {\n\tfrom { transform: translateY(100%); }\n\tto { transform: translateY(0); }\n}\n@keyframes pptx-tr-pan-to-top {\n\tfrom { transform: translateY(0); }\n\tto { transform: translateY(-100%); }\n}\n@keyframes pptx-tr-pan-from-top {\n\tfrom { transform: translateY(-100%); }\n\tto { transform: translateY(0); }\n}\n@keyframes pptx-tr-pan-to-bottom {\n\tfrom { transform: translateY(0); }\n\tto { transform: translateY(100%); }\n}\n"; /** Part 2: prism / reveal / ripple / shred / switch / vortex / warp / wheelReverse / window. */ export declare const P14_TRANSITION_KEYFRAMES_2 = "\n/* ── Prism: see `slide-transition-prism` (split out to keep this module\n under the per-file LOC budget) ─────────────────────────────────────── */\n\n@keyframes pptx-tr-prism-in-from-right {\n\tfrom { transform: perspective(800px) rotateY(-90deg) translateX(50%); opacity: 0; }\n\tto { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }\n}\n@keyframes pptx-tr-prism-out-to-left {\n\tfrom { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }\n\tto { transform: perspective(800px) rotateY(90deg) translateX(-50%); opacity: 0; }\n}\n@keyframes pptx-tr-prism-in-from-left {\n\tfrom { transform: perspective(800px) rotateY(90deg) translateX(-50%); opacity: 0; }\n\tto { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }\n}\n@keyframes pptx-tr-prism-out-to-right {\n\tfrom { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }\n\tto { transform: perspective(800px) rotateY(-90deg) translateX(50%); opacity: 0; }\n}\n@keyframes pptx-tr-prism-in-from-bottom {\n\tfrom { transform: perspective(800px) rotateX(90deg) translateY(50%); opacity: 0; }\n\tto { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }\n}\n@keyframes pptx-tr-prism-out-to-top {\n\tfrom { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }\n\tto { transform: perspective(800px) rotateX(-90deg) translateY(-50%); opacity: 0; }\n}\n@keyframes pptx-tr-prism-in-from-top {\n\tfrom { transform: perspective(800px) rotateX(-90deg) translateY(-50%); opacity: 0; }\n\tto { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }\n}\n@keyframes pptx-tr-prism-out-to-bottom {\n\tfrom { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }\n\tto { transform: perspective(800px) rotateX(90deg) translateY(50%); opacity: 0; }\n}\n\n/* ── Reveal (slide away reveal) ──────────────────────────────────── */\n@keyframes pptx-tr-reveal-out-to-right {\n\tfrom { transform: translateX(0); }\n\tto { transform: translateX(100%); }\n}\n@keyframes pptx-tr-reveal-out-to-left {\n\tfrom { transform: translateX(0); }\n\tto { transform: translateX(-100%); }\n}\n/* MEASURED: the incoming layer stays hidden for roughly the first half of the\n transition (a real black/background gap shows through), then fades in -\n not a flat 0.5->1 fade running the whole duration. */\n@keyframes pptx-tr-reveal-in {\n\t0% { opacity: 0; }\n\t50% { opacity: 0; }\n\t100% { opacity: 1; }\n}\n\n/* ── Ripple (expanding ring clip-path) ───────────────────────────── */\n@keyframes pptx-tr-ripple-in {\n\tfrom { clip-path: circle(0% at 50% 50%); opacity: 0.5; }\n\t30% { clip-path: circle(20% at 50% 50%); opacity: 0.7; }\n\t60% { clip-path: circle(50% at 50% 50%); opacity: 0.9; }\n\tto { clip-path: circle(75% at 50% 50%); opacity: 1; }\n}\n\n/* ── Shred (fragmented clip-path pieces) ─────────────────────────── */\n@keyframes pptx-tr-shred-strips-in {\n\tfrom { clip-path: inset(0 100% 0 0); opacity: 0; }\n\t30% { clip-path: inset(0 60% 0 0); opacity: 0.5; }\n\tto { clip-path: inset(0); opacity: 1; }\n}\n@keyframes pptx-tr-shred-rectangles-in {\n\tfrom { clip-path: inset(50%); opacity: 0; }\n\t40% { clip-path: inset(20%); opacity: 0.6; }\n\tto { clip-path: inset(0); opacity: 1; }\n}\n@keyframes pptx-tr-shred-out {\n\tfrom { opacity: 1; }\n\tto { opacity: 0; filter: blur(2px); }\n}\n\n/* ── Switch (flip/rotate swap) ───────────────────────────────────── */\n@keyframes pptx-tr-switch-in-from-right {\n\tfrom { transform: perspective(800px) rotateY(-180deg); opacity: 0; }\n\tto { transform: perspective(800px) rotateY(0deg); opacity: 1; }\n}\n@keyframes pptx-tr-switch-out-to-left {\n\tfrom { transform: perspective(800px) rotateY(0deg); opacity: 1; }\n\tto { transform: perspective(800px) rotateY(180deg); opacity: 0; }\n}\n@keyframes pptx-tr-switch-in-from-left {\n\tfrom { transform: perspective(800px) rotateY(180deg); opacity: 0; }\n\tto { transform: perspective(800px) rotateY(0deg); opacity: 1; }\n}\n@keyframes pptx-tr-switch-out-to-right {\n\tfrom { transform: perspective(800px) rotateY(0deg); opacity: 1; }\n\tto { transform: perspective(800px) rotateY(-180deg); opacity: 0; }\n}\n\n/* ── Vortex (rotate + scale spiral) ──────────────────────────────── */\n@keyframes pptx-tr-vortex-in {\n\tfrom { transform: rotate(720deg) scale(0); opacity: 0; }\n\tto { transform: rotate(0deg) scale(1); opacity: 1; }\n}\n@keyframes pptx-tr-vortex-out {\n\tfrom { transform: rotate(0deg) scale(1); opacity: 1; }\n\tto { transform: rotate(-720deg) scale(0); opacity: 0; }\n}\n\n/* ── Warp: see `slide-transition-warp` (COM-measured radial zoom blur,\n split out to keep this module under the per-file LOC budget) ────────── */\n\n@keyframes pptx-tr-warp-in {\n\t0% { transform: scale(0.25); opacity: 0; filter: blur(10px) brightness(1.8); }\n\t50% { transform: scale(0.85); opacity: 0.7; filter: blur(3px) brightness(1.3); }\n\t100% { transform: scale(1); opacity: 1; filter: blur(0) brightness(1); }\n}\n@keyframes pptx-tr-warp-out {\n\t0% { transform: scale(1); opacity: 1; filter: blur(0) brightness(1); }\n\t50% { transform: scale(0.85); opacity: 0.7; filter: blur(3px) brightness(1.3); }\n\t100% { transform: scale(0.25); opacity: 0; filter: blur(10px) brightness(1.8); }\n}\n@keyframes pptx-tr-warp-reverse-in {\n\t0% { transform: scale(3.2); opacity: 0; filter: blur(14px) brightness(2.2); }\n\t50% { transform: scale(1.7); opacity: 0.7; filter: blur(6px) brightness(1.5); }\n\t100% { transform: scale(1); opacity: 1; filter: blur(0) brightness(1); }\n}\n@keyframes pptx-tr-warp-reverse-out {\n\t0% { transform: scale(1); opacity: 1; filter: blur(0) brightness(1); }\n\t50% { transform: scale(1.7); opacity: 0.7; filter: blur(6px) brightness(1.5); }\n\t100% { transform: scale(3.2); opacity: 0; filter: blur(14px) brightness(2.2); }\n}\n\n\n/* ── WheelReverse (reverse wheel rotation) ───────────────────────── */\n@keyframes pptx-tr-wheel-reverse-in {\n\tfrom { clip-path: circle(0% at 50% 50%); transform: rotate(180deg); }\n\tto { clip-path: circle(75% at 50% 50%); transform: rotate(0deg); }\n}\n\n/* ── Window (scale from center with border) ──────────────────────────\n Same measured horz/vert meaning as Doors above (horz = horizontal split\n line opening vertically; vert = vertical split line opening horizontally). */\n@keyframes pptx-tr-window-horz {\n\tfrom { clip-path: inset(50% 0); }\n\tto { clip-path: inset(0 0); }\n}\n@keyframes pptx-tr-window-vert {\n\tfrom { clip-path: inset(0 50%); }\n\tto { clip-path: inset(0 0); }\n}\n@keyframes pptx-tr-window-out {\n\tfrom { opacity: 1; transform: scale(1); }\n\tto { opacity: 0; transform: scale(0.9); }\n}\n"; /** Both p14 keyframe blocks concatenated, for single `