fika-editor 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/embed/947.js +144 -0
  2. package/dist/embed/agentic-manifest.json +186 -11
  3. package/dist/embed/chunks/1131.css +1 -1
  4. package/dist/embed/chunks/1131.js +1 -1
  5. package/dist/embed/chunks/1505.js +8 -0
  6. package/dist/embed/chunks/1904.js +1 -1
  7. package/dist/embed/chunks/2020.js +43 -37
  8. package/dist/embed/chunks/2289.js +1 -1
  9. package/dist/embed/chunks/2796.js +1 -1
  10. package/dist/embed/chunks/2807.js +1 -1
  11. package/dist/embed/chunks/3030.js +1 -1
  12. package/dist/embed/chunks/3729.js +3 -3
  13. package/dist/embed/chunks/4552.js +1 -1
  14. package/dist/embed/chunks/4625.js +1 -1
  15. package/dist/embed/chunks/4891.js +2 -2
  16. package/dist/embed/chunks/4950.js +1 -1
  17. package/dist/embed/chunks/4975.js +5 -5
  18. package/dist/embed/chunks/5216.js +1 -1
  19. package/dist/embed/chunks/5792.js +1 -1
  20. package/dist/embed/chunks/627.js +1 -1
  21. package/dist/embed/chunks/6567.js +1 -1
  22. package/dist/embed/chunks/717.js +2 -2
  23. package/dist/embed/chunks/7175.js +1 -1
  24. package/dist/embed/chunks/7311.js +1 -1
  25. package/dist/embed/chunks/7594.js +1 -1
  26. package/dist/embed/chunks/7854.js +1 -1
  27. package/dist/embed/chunks/788.js +1 -1
  28. package/dist/embed/chunks/7916.js +1 -1
  29. package/dist/embed/chunks/8212.js +1 -1
  30. package/dist/embed/chunks/8239.js +1 -1
  31. package/dist/embed/chunks/8645.js +1 -1
  32. package/dist/embed/chunks/8716.js +3 -3
  33. package/dist/embed/chunks/9121.js +1 -1
  34. package/dist/embed/chunks/9465.js +2 -2
  35. package/dist/embed/fika-embed.css +1 -1
  36. package/dist/embed/fika-embed.js +3 -2
  37. package/dist/types/components/Button.d.ts +2 -1
  38. package/dist/types/components/ColorSwatches.d.ts +2 -1
  39. package/dist/types/components/Draggable.d.ts +9 -4
  40. package/dist/types/configs/animation.d.ts +2 -0
  41. package/dist/types/configs/font.d.ts +0 -2
  42. package/dist/types/configs/templates.d.ts +1 -5
  43. package/dist/types/embed/agentic/templates.d.ts +2 -1
  44. package/dist/types/embed/agentic/types.d.ts +57 -1
  45. package/dist/types/hooks/useScreening.d.ts +5 -3
  46. package/dist/types/i18n/i18n-types.d.ts +4 -4
  47. package/dist/types/store/index.d.ts +2 -2
  48. package/dist/types/store/slides.d.ts +18 -3
  49. package/dist/types/types/injectKey.d.ts +6 -0
  50. package/dist/types/utils/canvasHitTest.d.ts +14 -2
  51. package/dist/types/utils/commitQueue.d.ts +13 -0
  52. package/dist/types/utils/cssLength.d.ts +8 -0
  53. package/dist/types/utils/database.d.ts +6 -1
  54. package/dist/types/utils/element.d.ts +18 -0
  55. package/dist/types/utils/imageBitmapCache.d.ts +14 -2
  56. package/dist/types/utils/imageSize.d.ts +9 -0
  57. package/dist/types/utils/liveElementSize.d.ts +20 -1
  58. package/dist/types/utils/mediaIntern.d.ts +12 -0
  59. package/dist/types/utils/placeholderLayout.d.ts +25 -6
  60. package/dist/types/utils/prosemirror/commitEditor.d.ts +3 -0
  61. package/dist/types/utils/prosemirror/index.d.ts +1 -0
  62. package/dist/types/utils/screening.d.ts +10 -0
  63. package/dist/types/utils/shapePaint.d.ts +23 -0
  64. package/dist/types/utils/simpleShape.d.ts +5 -0
  65. package/dist/types/utils/slideOrder.d.ts +10 -0
  66. package/dist/types/utils/snap.d.ts +9 -0
  67. package/dist/types/utils/tableCellStyle.d.ts +12 -0
  68. package/dist/types/utils/tableStyleTarget.d.ts +3 -0
  69. package/dist/types/utils/textContrast.d.ts +25 -1
  70. package/dist/types/utils/textFit.d.ts +31 -13
  71. package/dist/types/views/Editor/Canvas/Operate/ResizeHandler.d.ts +2 -1
  72. package/dist/types/views/Editor/Thumbnails/paneSize.d.ts +7 -3
  73. package/dist/types/views/Editor/Thumbnails/useThumbnailVirtualizer.d.ts +1 -0
  74. package/dist/types/views/components/ThumbnailSlide/LiveSlideThumb.d.ts +21 -0
  75. package/dist/types/views/components/ThumbnailSlide/index.d.ts +8 -0
  76. package/dist/types/views/components/ThumbnailSlide/paintedSlide.d.ts +1 -1
  77. package/dist/types/views/components/ThumbnailSlide/thumbSnapshot.d.ts +54 -0
  78. package/dist/types/views/components/element/TableElement/CustomTextarea.d.ts +2 -1
  79. package/dist/types/views/components/element/hooks/useAutoShapeTextHeight.d.ts +3 -1
  80. package/docs/RELEASE.md +2 -0
  81. package/package.json +8 -11
  82. package/dist/embed/350.js +0 -164
  83. package/dist/types/previewRaster/index.d.ts +0 -9
  84. package/dist/types/previewRaster/painters/background.d.ts +0 -2
  85. package/dist/types/previewRaster/painters/booth.d.ts +0 -13
  86. package/dist/types/previewRaster/painters/chart.d.ts +0 -2
  87. package/dist/types/previewRaster/painters/code.d.ts +0 -2
  88. package/dist/types/previewRaster/painters/image.d.ts +0 -2
  89. package/dist/types/previewRaster/painters/index.d.ts +0 -3
  90. package/dist/types/previewRaster/painters/line.d.ts +0 -2
  91. package/dist/types/previewRaster/painters/media.d.ts +0 -2
  92. package/dist/types/previewRaster/painters/shape.d.ts +0 -2
  93. package/dist/types/previewRaster/painters/table.d.ts +0 -2
  94. package/dist/types/previewRaster/painters/text.d.ts +0 -2
  95. package/dist/types/previewRaster/planSlideRaster.d.ts +0 -19
  96. package/dist/types/previewRaster/rasterCache.d.ts +0 -19
  97. package/dist/types/previewRaster/scheduler.d.ts +0 -4
  98. package/dist/types/previewRaster/stagePool.d.ts +0 -36
  99. package/dist/types/previewRaster/stats.d.ts +0 -10
  100. package/dist/types/previewRaster/subscribeSlides.d.ts +0 -10
  101. package/dist/types/previewRaster/types.d.ts +0 -12
  102. package/dist/types/utils/elementPaint.d.ts +0 -129
  103. package/dist/types/views/components/element/ChartElement/chartBooth.d.ts +0 -2
  104. /package/dist/embed/{350.css → 947.css} +0 -0
  105. /package/dist/types/{previewRaster → utils}/diffPaintedSlide.d.ts +0 -0
@@ -0,0 +1,23 @@
1
+ import type { PPTShapeElement } from '../types/slides';
2
+ export declare const shapePathScale: (element: Pick<PPTShapeElement, 'width' | 'height' | 'viewBox'>) => {
3
+ x: number;
4
+ y: number;
5
+ };
6
+ /** Same transform the live editor SVG applies to `element.path`. */
7
+ export declare const shapePathTransform: (element: Pick<PPTShapeElement, 'width' | 'height' | 'viewBox'>) => string;
8
+ /**
9
+ * Editor-equivalent SVG (+ optional ProseMirror label). SnapDOM this instead of
10
+ * asking Konva to interpret PPTX/catalog arcs — browsers correct `A 50 50`
11
+ * radii, Konva does not.
12
+ */
13
+ export declare const shapePaintHtml: (element: PPTShapeElement, text?: {
14
+ body: string;
15
+ ink: string;
16
+ fontFamily: string;
17
+ align?: string;
18
+ inset?: [number, number, number, number];
19
+ lineHeight?: number;
20
+ letterSpacing?: number;
21
+ paragraphSpace?: number;
22
+ fitScale?: number;
23
+ }) => string;
@@ -0,0 +1,5 @@
1
+ import type { PPTShapeElement } from '../types/slides';
2
+ export declare const shapeTextIsEmpty: (html?: string) => boolean;
3
+ /** Imported PPTX rects and formula rects that fill the viewBox. */
4
+ export declare const isAxisAlignedRectPath: (path: string, viewBox: [number, number]) => boolean;
5
+ export declare const isSimpleShape: (element: PPTShapeElement) => boolean;
@@ -1,3 +1,13 @@
1
1
  import type { Slide } from '../types/slides';
2
2
  /** Reorder slides without cloning unchanged slide objects (elements/background stay referentially equal). */
3
3
  export declare const reorderSlidesPreservingIdentity: (slides: readonly Slide[], oldIndex: number, newIndex: number) => Slide[];
4
+ export declare const insertSlidesPreservingIdentity: (slides: readonly Slide[], index: number, incoming: readonly Slide[]) => Slide[];
5
+ export declare const deleteSlidesPreservingIdentity: (slides: readonly Slide[], slideIds: readonly string[]) => {
6
+ slides: Slide[];
7
+ deletedIndexes: number[];
8
+ };
9
+ export declare const slideIndexAfterDelete: (prevIndex: number, prevSlides: readonly Slide[], deletedIds: ReadonlySet<string>, nextLength: number, deletedIndexes: readonly number[]) => number;
10
+ export declare const moveSlidePreservingIdentity: (slides: readonly Slide[], fromIndex: number, toIndex: number) => {
11
+ slides: Slide[];
12
+ index: number;
13
+ };
@@ -6,6 +6,8 @@ export declare const SNAP_MATCH = 0.51;
6
6
  export declare const SLIDE_MARGIN = 40;
7
7
  export declare const RELATED_GAP = 240;
8
8
  export declare const MAX_CTRL_MEASURES = 8;
9
+ /** Same-row/column objects beat a slightly closer distant line. */
10
+ export declare const RELATION_WEIGHT = 4;
9
11
  export type SnapKind = 'edge' | 'center' | 'canvas' | 'spacing' | 'size' | 'grid' | 'measure';
10
12
  export type SnapMode = 'smart' | 'grid';
11
13
  export interface SnapGuide {
@@ -35,6 +37,8 @@ export interface SnapOptions {
35
37
  gridSize: number;
36
38
  threshold?: number;
37
39
  index?: SnapIndex;
40
+ /** When set, append Ctrl distance badges for the already-queried k-set. */
41
+ ctrlMeasures?: boolean;
38
42
  }
39
43
  /** Search pad for the per-move Flatbush query: snap threshold or related-object reach. */
40
44
  export declare const snapQueryPad: (threshold?: number) => number;
@@ -62,6 +66,11 @@ export interface ResizeSnapOptions extends SnapOptions {
62
66
  resizeHeight?: boolean;
63
67
  }
64
68
  export declare const snapResizePoint: (currentX: number | null, currentY: number | null, others: SnapBox[], options: ResizeSnapOptions) => SnapResult;
69
+ /**
70
+ * Cross-axis for a distance badge: stay on the moving box.
71
+ * Shared row/column uses the overlap; otherwise project onto the moving center.
72
+ */
73
+ export declare const projectMeasureCross: (moving0: number, moving1: number, other0: number, other1: number) => number;
65
74
  /**
66
75
  * Ctrl-held distance badges: adjacent gaps along live guides, both axes to
67
76
  * the most related object, nearest same-row/column neighbors, and slide margins.
@@ -0,0 +1,12 @@
1
+ import type { TableCellStyle } from '../types/slides';
2
+ export { rememberTableStyleTarget, tableStyleTarget } from './tableStyleTarget';
3
+ /**
4
+ * Persist any live cell draft, then patch cell styles on the store grid.
5
+ * Style panels only pass the style fields — they must not clone table data.
6
+ */
7
+ export declare function applyTableCellStyles(style: Partial<TableCellStyle>, options?: {
8
+ elementId?: string;
9
+ cells?: string[];
10
+ allCells?: boolean;
11
+ history?: boolean;
12
+ }): boolean;
@@ -0,0 +1,3 @@
1
+ /** Keep the last in-cell style target so Present/deselect cannot widen the next fill. */
2
+ export declare function rememberTableStyleTarget(elementId: string, cells: string[]): void;
3
+ export declare function tableStyleTarget(elementId: string, cells?: string[]): string[];
@@ -1,4 +1,4 @@
1
- import type { Gradient, PPTElement, PPTTableElement, Slide, SlideBackground } from '../types/slides';
1
+ import type { Gradient, PPTElement, PPTShapeElement, PPTTableElement, PPTTextElement, Slide, SlideBackground } from '../types/slides';
2
2
  /**
3
3
  * Painter's-algorithm text contrast repair for AI-imported decks.
4
4
  *
@@ -122,6 +122,30 @@ export declare const resolveElementDefaultFontColor: (preferred: string, options
122
122
  background?: SlideBackground;
123
123
  fallbackSurface?: string;
124
124
  }) => string;
125
+ export type LiveTextPaintOptions = {
126
+ fill?: string;
127
+ background?: SlideBackground;
128
+ fallbackSurface?: string;
129
+ themeFontColor?: string;
130
+ /** The text/shape being painted. Own fill/gradient win; otherwise under-paints. */
131
+ element?: PPTTextElement | PPTShapeElement;
132
+ /** Painter-order siblings so overlay labels see the chip/card underneath. */
133
+ elements?: PPTElement[];
134
+ };
135
+ /**
136
+ * Surfaces the text actually sits on — same query as import contrast.
137
+ * Own opaque fill/gradient first; otherwise the topmost paint under the box.
138
+ */
139
+ export declare const resolveTextPaintSurfaces: (el: PPTTextElement | PPTShapeElement | undefined, options?: LiveTextPaintOptions) => string[];
140
+ /**
141
+ * Single paint-time contrast pass for the live editor and the preview raster.
142
+ * Surfaces match {@link fixSlideTextContrast}: overlay labels on a chip use
143
+ * the chip, not the slide paper. Default inks rewrite to the same hex.
144
+ */
145
+ export declare const resolveLiveTextPaint: (preferred: string | undefined, html: string, options?: LiveTextPaintOptions) => {
146
+ ink: string;
147
+ html: string;
148
+ };
125
149
  /**
126
150
  * Chart axis / legend / label ink. Same rules as text: default greys / black /
127
151
  * white snap to {@link preferredInk} on the chart fill, else the slide.
@@ -37,6 +37,18 @@ export interface TextFitBlock {
37
37
  listIndentPx?: number;
38
38
  /** `ul`/`ol` padding-inline-start in em, when authored as em. */
39
39
  listIndentEm?: number;
40
+ /**
41
+ * Mixed-size runs inside one paragraph, measured exactly: each run gets its
42
+ * own font and pretext's rich-inline line breaker, so wrapping and per-line
43
+ * heights match what the browser paints (a 57px body with one 120px word
44
+ * wraps like 57px and only that one line is 120px tall).
45
+ */
46
+ runs?: Array<{
47
+ text: string;
48
+ size: number;
49
+ bold?: boolean;
50
+ italic?: boolean;
51
+ }>;
40
52
  }
41
53
  export interface MeasureBlocksOptions {
42
54
  /** Box content width in px (insets already removed). */
@@ -100,12 +112,6 @@ export declare function innerBoxFromLiveStyles(box: HTMLElement | null | undefin
100
112
  };
101
113
  export declare function contentBoxOfHost(host: HTMLElement | null | undefined): HTMLElement | null;
102
114
  export declare function measureUnzoomedScrollHeight(host: HTMLElement, innerWidth: number): number;
103
- /**
104
- * Total wrapped height (px) of `blocks` laid out in a column of `innerWidth`,
105
- * with each block's font size multiplied by `sizeScale`. Each block is measured
106
- * independently with pretext, then summed with the (unscaled, px-fixed)
107
- * inter-block gap. Returns 0 for an empty input.
108
- */
109
115
  export declare function measureTextBlocksHeight(blocks: TextFitBlock[], options: MeasureBlocksOptions): number;
110
116
  export interface FitFontScaleOptions {
111
117
  innerWidth: number;
@@ -157,11 +163,10 @@ export declare function createFitMeasureSession(html: string, options: {
157
163
  /** Resize hot path: pure `layout()` over cached prepare handles. */
158
164
  export declare function measureSessionHeight(session: FitMeasureSession, innerWidth: number, blockSpace?: number, bulletIndent?: number): number;
159
165
  export declare function fitZoomScaleFromSession(session: FitMeasureSession, innerWidth: number, innerHeight: number, blockSpace?: number): number;
160
- /**
161
- * One-shot locked-box scale for a rich-text HTML string. Editor resize keeps a
162
- * cached session; preview/export call this so they shrink with the same math.
163
- */
164
- export declare function textFitScaleForHtml(html: string, options: {
166
+ /** Rendered spans may carry calc(var(--text-fit-scale,...)); measurement wants authored px. */
167
+ declare const stripFitScale: (html: string) => string;
168
+ export declare const stripFitScaleForProbe: typeof stripFitScale;
169
+ type FitScaleOptions = {
165
170
  innerWidth: number;
166
171
  innerHeight: number;
167
172
  defaultFontFamily?: string;
@@ -170,7 +175,18 @@ export declare function textFitScaleForHtml(html: string, options: {
170
175
  letterSpacing?: number;
171
176
  blockSpace?: number;
172
177
  locale?: string;
173
- }): number;
178
+ };
179
+ /**
180
+ * Persist a DOM-verified correction: the editor measured the REAL rendered
181
+ * height and found the searched scale overflowing. Remembered so the rail,
182
+ * later applies, and export reuse the corrected value instead of re-overflow.
183
+ */
184
+ export declare function rememberFitScale(html: string, options: FitScaleOptions, scale: number): void;
185
+ /**
186
+ * One-shot locked-box scale for a rich-text HTML string. Editor resize keeps a
187
+ * cached session; preview/export call this so they shrink with the same math.
188
+ */
189
+ export declare function textFitScaleForHtml(html: string, options: FitScaleOptions): number;
174
190
  export interface ExtractedContent {
175
191
  blocks: TextFitBlock[];
176
192
  }
@@ -181,7 +197,8 @@ export interface ExtractOptions {
181
197
  /**
182
198
  * Parse a Fika rich-text HTML string into measurable blocks. Each list item
183
199
  * and top-level paragraph/quote becomes one block; a block's representative font
184
- * size is the largest inline size in it (so measurement never under-estimates).
200
+ * size is the largest inline size in it (so the clip pad never under-
201
+ * estimates), while wrapping measures the mixed-size run profile.
185
202
  * Returns no blocks when there's no DOM parser or no text. List items are tagged
186
203
  * so the marker indent is accounted for.
187
204
  */
@@ -193,3 +210,4 @@ export declare function extractFitBlocksFromHtml(html: string, options: ExtractO
193
210
  * scale >= 1 (or a non-DOM context) returns the HTML unchanged.
194
211
  */
195
212
  export declare function scaleHtmlFontSizes(html: string, scale: number): string;
213
+ export {};
@@ -5,7 +5,8 @@ export type IResizeHandlerProps = {
5
5
  rotate?: number;
6
6
  className?: string;
7
7
  style?: CSSProperties;
8
+ 'data-line-handle'?: string;
8
9
  onMouseDown?: (e: ReactMouseEvent<HTMLDivElement>) => void;
9
10
  };
10
- declare const ResizeHandler: import("react").MemoExoticComponent<({ type, rotate, className, style, onMouseDown }: IResizeHandlerProps) => import("react").JSX.Element>;
11
+ declare const ResizeHandler: import("react").MemoExoticComponent<({ type, rotate, className, style, onMouseDown, 'data-line-handle': lineHandle }: IResizeHandlerProps) => import("react").JSX.Element>;
11
12
  export default ResizeHandler;
@@ -2,8 +2,8 @@ export declare const PREVIEW_MIN_PANE = 120;
2
2
  export declare const PREVIEW_DEFAULT_PANE = 168;
3
3
  export declare const PREVIEW_MAX_PANE = 420;
4
4
  export declare const PREVIEW_THUMB_INSET = 48;
5
- export declare const PREVIEW_SUPER_SAMPLE = 2;
6
- export declare const PREVIEW_MAX_WORKING = 1024;
5
+ export declare const PREVIEW_PANE_RESIZE_COMMIT_MS = 120;
6
+ export type PreviewWorkingQuality = 'full' | 'rail' | 'lq';
7
7
  type DestPublishHandler = () => void;
8
8
  export type PreviewDestSize = {
9
9
  cssWidth: number;
@@ -11,8 +11,12 @@ export type PreviewDestSize = {
11
11
  dpr: number;
12
12
  workingSlideWidth: number;
13
13
  };
14
- export declare const previewWorkingWidth: (destWidth: number, pixelRatio: number) => number;
14
+ export declare const isPaneDragging: () => boolean;
15
+ export declare const beginPaneDrag: () => void;
16
+ export declare const endPaneDrag: () => void;
17
+ export declare const subscribePaneLive: (listener: (contentWidth: number) => void) => () => void;
15
18
  export declare const setPreviewDestPublishHandler: (fn: DestPublishHandler | null) => void;
19
+ export declare const setPreviewDestLiveHandler: (fn: DestPublishHandler | null) => void;
16
20
  export declare const setPreviewPaneWidth: (width: number) => void;
17
21
  export declare const setPreviewViewportRatio: (ratio: number) => void;
18
22
  export declare const getPreviewDestSize: () => PreviewDestSize;
@@ -7,6 +7,7 @@ export type ThumbnailVirtualizerApi = {
7
7
  virtualizer: Virtualizer<HTMLDivElement, Element>;
8
8
  virtualItems: VirtualItem[];
9
9
  visibleSlideIds: string[];
10
+ pinnedSlideIds: string[];
10
11
  thumbHeight: number;
11
12
  dest: PreviewDestSize;
12
13
  };
@@ -0,0 +1,21 @@
1
+ import type { Slide } from '../../../types/slides';
2
+ export type ILiveSlideThumbProps = {
3
+ slide: Slide;
4
+ width: number;
5
+ /** Opt into the identity-keyed snapshot cache (editor rail only). */
6
+ snapshot?: boolean;
7
+ };
8
+ /**
9
+ * A thumbnail that IS the slide: the genuine ScreenSlide tree, scaled to the
10
+ * thumbnail box. With `snapshot` enabled, a row that already has a fresh
11
+ * bitmap renders only the <img>. A row without one mounts the live tree —
12
+ * the virtualizer screenshots that tree with snapdom before tearing the row
13
+ * down, so the next visit is the bitmap. Nothing is captured ahead of the
14
+ * viewport; only a row that was actually shown is snapshotted on leave.
15
+ *
16
+ * During a gutter drag only this light wrapper tracks the live width; the
17
+ * mounted ScreenSlide keeps its drag-start scale and is visually scaled by a
18
+ * composited transform — the heavy tree never re-renders mid-drag.
19
+ */
20
+ declare const LiveSlideThumb: import("react").MemoExoticComponent<(props: ILiveSlideThumbProps) => import("react").JSX.Element>;
21
+ export default LiveSlideThumb;
@@ -7,7 +7,15 @@ export type IThumbnailSlideProps = {
7
7
  visible?: boolean;
8
8
  showPlaceholders?: boolean;
9
9
  className?: string;
10
+ /** Opt into the identity-keyed snapshot cache (editor rail only). */
11
+ snapshot?: boolean;
10
12
  };
11
13
  export declare function areThumbnailSlidePropsEqual(prev: IThumbnailSlideProps, next: IThumbnailSlideProps): boolean;
14
+ /**
15
+ * The thumbnail IS the slide: the real ScreenSlide DOM scaled into the thumb
16
+ * box (see LiveSlideThumb). The rail stays faithful to the editor canvas by
17
+ * construction and updates live while editing — no raster pipeline, no
18
+ * per-element capture booths, nothing to fall behind.
19
+ */
12
20
  declare const ThumbnailSlide: import("react").MemoExoticComponent<(props: IThumbnailSlideProps) => import("react").JSX.Element>;
13
21
  export default ThumbnailSlide;
@@ -1,5 +1,5 @@
1
1
  import type { Slide } from '../../../types/slides';
2
- import { diffPaintedSlide, type PaintedSlide, type PaintedSlideDiff } from '../../../previewRaster/diffPaintedSlide';
2
+ import { diffPaintedSlide, type PaintedSlide, type PaintedSlideDiff } from '../../../utils/diffPaintedSlide';
3
3
  export type { PaintedSlide, PaintedSlideDiff };
4
4
  export { diffPaintedSlide };
5
5
  export type RailSlideMeta = {
@@ -0,0 +1,54 @@
1
+ import type { Slide } from '../../../types/slides';
2
+ export type ThumbSnapshot = {
3
+ url: string;
4
+ cssWidth: number;
5
+ cssHeight: number;
6
+ };
7
+ export type ThumbSnapshotDeps = {
8
+ slideId: string;
9
+ slide: Slide | undefined;
10
+ theme: unknown;
11
+ viewportRatio: number;
12
+ viewportSize: number;
13
+ cssWidth: number;
14
+ dpr: number;
15
+ };
16
+ export declare const thumbSnapshotStats: {
17
+ hits: number;
18
+ misses: number;
19
+ captures: number;
20
+ failed: number;
21
+ hostileSkips: number;
22
+ evictions: number;
23
+ invalidated: number;
24
+ captureMs: number[];
25
+ };
26
+ /** Re-render when snapshots arrive or are cleared. */
27
+ export declare const useThumbSnapshotVersion: () => number;
28
+ /**
29
+ * Fresh lookup for the current render. A stored snapshot whose key no longer
30
+ * matches is revoked on the spot — stale pixels are never handed out.
31
+ */
32
+ export declare function lookupThumbSnapshot(deps: ThumbSnapshotDeps): ThumbSnapshot | null;
33
+ export declare function clearThumbSnapshots(): void;
34
+ export declare function hasFreshSnapshotFor(slideId: string): boolean;
35
+ export declare function canCaptureThumb(slideId: string): boolean;
36
+ export declare const isRailScrollIdle: () => boolean;
37
+ export declare function requestThumbCapture(deps: ThumbSnapshotDeps, getNode: () => HTMLElement | null): void;
38
+ /** Screenshot a live thumb now — used before the virtualizer tears the row down. */
39
+ export declare function requestTeardownCapture(deps: ThumbSnapshotDeps, getNode: () => HTMLElement | null): Promise<boolean>;
40
+ export declare function teardownThumbSnapshot(slideId: string, getNode: () => HTMLElement | null): Promise<boolean>;
41
+ export declare const readThumbSnapshotReport: () => {
42
+ hits: number;
43
+ misses: number;
44
+ captures: number;
45
+ failed: number;
46
+ hostileSkips: number;
47
+ evictions: number;
48
+ invalidated: number;
49
+ captureMs: number[];
50
+ captureMsAvg: number;
51
+ captureMsMax: number;
52
+ cached: number;
53
+ hostile: number;
54
+ };
@@ -1,11 +1,12 @@
1
1
  import { type CSSProperties } from 'react';
2
+ export type TableCellCommitSource = 'blur' | 'unmount';
2
3
  export type ICustomTextareaProps = {
3
4
  value?: string;
4
5
  className?: string;
5
6
  style?: CSSProperties;
6
7
  } & {
7
8
  onUpdateValue?: (payload: string) => void;
8
- onCommitValue?: (payload: string) => void;
9
+ onCommitValue?: (payload: string, source?: TableCellCommitSource) => void;
9
10
  onInsertExcelData?: (payload: string[][]) => void;
10
11
  };
11
12
  declare const CustomTextarea: import("react").MemoExoticComponent<(props: ICustomTextareaProps) => import("react").JSX.Element>;
@@ -1,2 +1,4 @@
1
1
  import type { TextInset } from '../../../../types/slides';
2
- export declare function useAutoShapeTextHeight(enabled: boolean, elementId: string, inset: TextInset): import("react").RefObject<HTMLDivElement>;
2
+ export declare function useAutoShapeTextHeight(enabled: boolean, elementId: string, inset: TextInset, contentHost?: {
3
+ readonly current: HTMLElement | null;
4
+ }): import("react").RefObject<HTMLDivElement>;
package/docs/RELEASE.md CHANGED
@@ -11,4 +11,6 @@ On npmjs.com → `fika-editor` → Settings → Trusted publishing, the GitHub A
11
11
 
12
12
  Do not store an `NPM_TOKEN` for publish. The workflow requests `id-token: write` and publishes with no auth token so npm exchanges the OIDC token.
13
13
 
14
+ Release commits, tags, and GitHub releases are authored by the `fika-bot` GitHub App (mug logo). Store `FIKA_BOT_CLIENT_ID` as a repository variable and `FIKA_BOT_PRIVATE_KEY` as a repository secret. Do not commit the `.pem`.
15
+
14
16
  The published tarball is the prebuilt embed (`dist/embed` + `dist/types`). `dist/` stays gitignored; the workflow runs `build:embed`, packs with the npm next to Node (not Bun's PATH shim), verifies that `.tgz` with `tar`, then publishes the same file. `prepack` / `prepublishOnly` refuse a docs-only tarball if those artifacts are missing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fika-editor",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "Fika presentation editor embed bundle with a typed agentic bridge.",
5
5
  "type": "module",
6
6
  "main": "dist/embed/fika-embed.js",
@@ -46,7 +46,7 @@
46
46
  "dev": "rsbuild dev",
47
47
  "doctor": "react-doctor --no-telemetry",
48
48
  "build": "run-p type-check \"build-only {@}\" --",
49
- "build:embed": "node scripts/run-i18n.mjs --no-watch && npm run build:types && rsbuild build --config rsbuild.config.embed.ts && node scripts/scope-embed-css.mjs && node scripts/extract-embed-fonts.mjs && node scripts/copy-embed-public.mjs && node scripts/generate-agentic-manifest.mjs",
49
+ "build:embed": "node scripts/run-i18n.mjs --no-watch && npm run build:types && rsbuild build --config rsbuild.config.embed.ts && node scripts/rewrite-embed-base-uri.mjs && node scripts/scope-embed-css.mjs && node scripts/extract-embed-fonts.mjs && node scripts/copy-embed-public.mjs && node scripts/generate-agentic-manifest.mjs",
50
50
  "agentic:manifest": "node scripts/generate-agentic-manifest.mjs",
51
51
  "build:types": "node -e \"require('node:fs').rmSync('dist/types',{recursive:true,force:true})\" && tsc -p tsconfig.types.json && node scripts/rewrite-embed-types.mjs",
52
52
  "prepack": "node scripts/verify-embed-pack.mjs",
@@ -56,13 +56,7 @@
56
56
  "build-only": "rsbuild build",
57
57
  "type-check": "tsc -p tsconfig.app.json --noEmit --pretty false",
58
58
  "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
59
- "test": "rstest",
60
- "test:live-size": "node scripts/check-live-element-size.mjs",
61
- "test:resize-elements:e2e": "node scripts/e2e-resize-elements.mjs",
62
- "test:resize-commit-match:e2e": "node scripts/e2e-resize-commit-match.mjs",
63
- "test:resize-shapes:e2e": "node scripts/e2e-resize-shapes.mjs",
64
- "test:live-paint": "node scripts/check-live-element-paint.mjs",
65
- "test:live-paint:e2e": "node scripts/e2e-live-paint.mjs",
59
+ "test": "node scripts/test.mjs",
66
60
  "i18n": "node scripts/run-i18n.mjs",
67
61
  "i18n:build": "node scripts/run-i18n.mjs --no-watch"
68
62
  },
@@ -86,7 +80,7 @@
86
80
  "@dnd-kit/core": "^6.3.1",
87
81
  "@dnd-kit/sortable": "^10.0.0",
88
82
  "@dnd-kit/utilities": "^3.2.2",
89
- "pptxgenjs-plus": "^4.1.17",
83
+ "@karibash/pixel-units": "^2.3.0",
90
84
  "@tanstack/react-virtual": "^3.14.9",
91
85
  "@use-gesture/react": "^10.3.1",
92
86
  "@use-gesture/vanilla": "^10.3.1",
@@ -108,7 +102,6 @@
108
102
  "html-to-image": "^1.11.13",
109
103
  "immer": "^11.1.16",
110
104
  "jszip": "^3.10.1",
111
- "konva": "^10.3.0",
112
105
  "lucide-react": "^1.31.0",
113
106
  "markdown-it": "^15.0.0",
114
107
  "markdown-it-texmath": "^1.0.0",
@@ -119,7 +112,9 @@
119
112
  "nanoid": "^6.0.1",
120
113
  "number-precision": "^1.6.0",
121
114
  "overlayscrollbars": "^2.16.0",
115
+ "parse5": "^8.0.1",
122
116
  "perfect-freehand": "^1.2.3",
117
+ "pptxgenjs-plus": "^4.1.17",
123
118
  "pptxtojson": "npm:@lofcz/pptxtojson@^2.2.5",
124
119
  "prosemirror-commands": "^1.7.2",
125
120
  "prosemirror-dropcursor": "^1.8.3",
@@ -134,7 +129,9 @@
134
129
  "prosemirror-view": "^1.42.2",
135
130
  "rbush": "^4.0.1",
136
131
  "react-resizable-panels": "^4.12.2",
132
+ "render-tag": "^0.1.29",
137
133
  "shiki": "^4.4.3",
134
+ "style-to-object": "^2.0.2",
138
135
  "svg-pathdata": "^9.0.0",
139
136
  "tinycolor2": "^1.6.0",
140
137
  "tippy.js": "^6.3.7",