fika-editor 3.0.2 → 3.0.3

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 (46) hide show
  1. package/README.md +8 -0
  2. package/dist/embed/{947.js → 183.js} +15 -15
  3. package/dist/embed/_e2e-statika.json +10909 -0
  4. package/dist/embed/agentic-manifest.json +4 -4
  5. package/dist/embed/chunks/1131.css +1 -1
  6. package/dist/embed/chunks/1131.js +1 -1
  7. package/dist/embed/chunks/1668.js +1 -1
  8. package/dist/embed/chunks/2595.js +1 -0
  9. package/dist/embed/chunks/2807.js +1 -1
  10. package/dist/embed/chunks/4467.js +1 -1
  11. package/dist/embed/chunks/5216.js +1 -1
  12. package/dist/embed/fika-embed.css +1 -1
  13. package/dist/embed/fika-embed.js +9 -3
  14. package/dist/types/components/Draggable.d.ts +1 -1
  15. package/dist/types/components/Slider.d.ts +1 -0
  16. package/dist/types/configs/animation.d.ts +1 -1
  17. package/dist/types/configs/transitions.d.ts +28 -0
  18. package/dist/types/embed/agentic/types.d.ts +7 -0
  19. package/dist/types/embed/types.d.ts +8 -0
  20. package/dist/types/i18n/i18n-types.d.ts +202 -34
  21. package/dist/types/paint/rasterResources.d.ts +7 -0
  22. package/dist/types/paint/scheduler.d.ts +17 -0
  23. package/dist/types/paint/slidePainter.d.ts +17 -0
  24. package/dist/types/paint/textPainter.d.ts +31 -0
  25. package/dist/types/store/importConfirm.d.ts +6 -1
  26. package/dist/types/store/slides.d.ts +12 -5
  27. package/dist/types/types/slides.d.ts +3 -2
  28. package/dist/types/utils/elementOutline.d.ts +33 -3
  29. package/dist/types/utils/exportFonts.d.ts +7 -3
  30. package/dist/types/utils/importApply.d.ts +10 -0
  31. package/dist/types/utils/importTransition.d.ts +19 -0
  32. package/dist/types/utils/layerStack.d.ts +24 -0
  33. package/dist/types/utils/liveElementOffset.d.ts +6 -5
  34. package/dist/types/utils/mediaIntern.d.ts +9 -0
  35. package/dist/types/utils/textFit.d.ts +14 -6
  36. package/dist/types/views/Editor/Canvas/LayerStackPanel.d.ts +14 -0
  37. package/dist/types/views/Editor/Toolbar/common/ElementOutline.d.ts +2 -0
  38. package/dist/types/views/components/ThumbnailSlide/CanvasSlideThumb.d.ts +11 -0
  39. package/dist/types/views/components/ThumbnailSlide/index.d.ts +2 -7
  40. package/package.json +15 -11
  41. package/dist/embed/chunks/1505.js +0 -8
  42. package/dist/embed/chunks/1932.js +0 -1
  43. package/dist/embed/chunks/5901.js +0 -1
  44. package/dist/types/views/components/ThumbnailSlide/LiveSlideThumb.d.ts +0 -21
  45. package/dist/types/views/components/ThumbnailSlide/thumbSnapshot.d.ts +0 -54
  46. /package/dist/embed/{947.css → 183.css} +0 -0
@@ -1,10 +1,40 @@
1
- import type { LineStyleType, PPTElementOutline } from '../types/slides';
2
- /** Clamp corner radius to half the shorter box side. */
1
+ import { type LineStyleType, type PPTElementOutline, type PPTShapeElement } from '../types/slides';
2
+ /** Clamp a resolved pixel corner radius to half the shorter box side. */
3
3
  export declare const clampOutlineRadius: (radius: number, width: number, height: number) => number;
4
+ /** Pixel radius for paint/CSS. `radius` is 0–1 of max rounding, or legacy px when `> 1`. */
5
+ export declare const resolveOutlineRadiusPx: (radius: number | undefined, width: number, height: number) => number;
6
+ /** Slider / label percent (0–100) for an authored outline radius. */
7
+ export declare const outlineRadiusToPercent: (radius: number | undefined, width: number, height: number) => number;
8
+ export declare const percentToOutlineRadius: (percent: number) => number;
4
9
  export declare const outlineRadiusCss: (radius: number | undefined, width: number, height: number) => string | undefined;
10
+ /**
11
+ * Rounded rect in local units. `rx`/`ry` are elliptical radii of that space
12
+ * (circular after a matching non-uniform scale). Skips zero-length edges so
13
+ * 100% rounding is a pill/circle instead of collapsed quadratic chamfers.
14
+ */
15
+ export declare const roundedRectEllipsePath: (width: number, height: number, rx: number, ry: number) => string;
16
+ /** Circular-corner rounded rect in pixel space. 100% radius → pill / circle. */
17
+ export declare const roundedRectArcPath: (width: number, height: number, radiusPx: number) => string;
5
18
  /** SVG path for a rectangular outline (optionally rounded). */
6
19
  export declare const roundedRectOutlinePath: (width: number, height: number, radius?: number) => string;
7
- /** pptxgenjs `rectRadius` is 0–1 relative to the shorter side. */
20
+ /** Rectangles and rectangle-family formulas the border-radius slider can round. */
21
+ export declare const isRoundableRectShape: (el: Pick<PPTShapeElement, 'path' | 'viewBox' | 'pathFormula'>) => boolean;
22
+ /**
23
+ * Path the editor / painter / hit-test should use. Outline radius is a 0–1
24
+ * fraction of max rounding; viewBox scale keeps the corners circular.
25
+ */
26
+ export declare const resolveShapePaintPath: (el: PPTShapeElement) => string;
27
+ /** Keep ROUND_RECT keypoints / path in sync when the radius slider moves. */
28
+ export declare const shapePropsForOutlineRadius: (el: PPTShapeElement, radius: number) => Partial<PPTShapeElement>;
29
+ export declare const outlineElementPatch: (el: {
30
+ type: string;
31
+ }, outline: PPTElementOutline, radiusChanged?: boolean) => {
32
+ outline: PPTElementOutline;
33
+ } & Partial<PPTShapeElement>;
34
+ /**
35
+ * pptxgenjs-plus `rectRadius` (ECMA-376 `a:gd name="adj"` / 50000).
36
+ * 0 = sharp corners, 1 = maximum rounding, 0.2 = 20%.
37
+ */
8
38
  export declare const outlineRadiusToPptxRectRadius: (radius: number, width: number, height: number) => number;
9
39
  /** pptxtojson emits border colors as a structured solid/gradient object. */
10
40
  export type PptxBorderColor = string | {
@@ -3,9 +3,13 @@
3
3
  *
4
4
  * Collects the non-system font families actually used in the deck, fetches their
5
5
  * woff2 bytes (bundled via `new URL(...)` so Vite emits them), decompresses
6
- * woff2 → TTF (via wawoff2), and returns `AddFontOptions[]` for `pptx.addFont()`.
7
- * PPTX embeds fonts as EOT-wrapped data and pptxgenjs handles TTF/OTF directly,
8
- * so the only required step is woff2 → TTF decompression.
6
+ * woff2 → TTF (via woff-lib, pure TS), and returns `AddFontOptions[]` for
7
+ * `pptx.addFont()`. PPTX embeds fonts as EOT-wrapped data and pptxgenjs handles
8
+ * TTF/OTF directly, so the only required step is woff2 → TTF decompression.
9
+ *
10
+ * woff-lib replaced wawoff2 here: wawoff2 is a Node-targeted Emscripten binary
11
+ * whose `onRuntimeInitialized` promise never resolves when the runtime fails to
12
+ * boot inside a bundled web build, hanging exports forever with no error.
9
13
  */
10
14
  import type pptxgen from 'pptxgenjs-plus';
11
15
  type AddFontOptions = Parameters<pptxgen['addFont']>[0];
@@ -1,3 +1,5 @@
1
+ import type { TurningMode } from '../types/slides';
2
+ import type { ImportTurningModeInput } from './importTransition';
1
3
  export type ImportApplyMode = 'replace' | 'append';
2
4
  export interface ImportApplyOptions {
3
5
  /**
@@ -5,6 +7,14 @@ export interface ImportApplyOptions {
5
7
  * Default is `replace`.
6
8
  */
7
9
  mode?: ImportApplyMode;
10
+ /**
11
+ * Override imported slide transitions. A single mode applies to every slide;
12
+ * an array or index map sets individual slides (missing entries keep the
13
+ * file transition, or `defaultTurningMode` / Rise when the file has none).
14
+ */
15
+ turningMode?: ImportTurningModeInput;
16
+ /** Fallback when a slide has no file transition and no per-slide override. */
17
+ defaultTurningMode?: TurningMode;
8
18
  /**
9
19
  * Legacy alias: `true` replace, `false` append.
10
20
  * An empty deck (0 slides) is always replaced.
@@ -0,0 +1,19 @@
1
+ import type { Slide, TurningMode } from '../types/slides';
2
+ export declare const isTurningMode: (value: unknown) => value is TurningMode;
3
+ /** One mode for every slide, or a per-slide list / index map. */
4
+ export type ImportTurningModeInput = TurningMode | Array<TurningMode | null | undefined> | Record<number, TurningMode>;
5
+ export type ImportTransitionOptions = {
6
+ turningMode?: ImportTurningModeInput;
7
+ /** Used when a slide has no file transition and no per-slide override. */
8
+ defaultTurningMode?: TurningMode;
9
+ };
10
+ export type AppliedImportTransitions = {
11
+ slides: Slide[];
12
+ /** Set when every imported slide received the same explicit override. */
13
+ uniformMode?: TurningMode;
14
+ };
15
+ /**
16
+ * Accept a single mode, an index-aligned array, or a 0- or 1-based index map.
17
+ */
18
+ export declare const parseImportTurningMode: (value: unknown) => ImportTurningModeInput | undefined;
19
+ export declare const applyImportTransitions: (slides: Slide[], options?: ImportTransitionOptions) => AppliedImportTransitions;
@@ -0,0 +1,24 @@
1
+ import type { PPTElement } from '../types/slides';
2
+ /**
3
+ * One row of the Alt+Click layer picker: an element (or a whole group)
4
+ * whose visual box contains the probed point.
5
+ */
6
+ export interface LayerStackEntry {
7
+ /** Representative element — for groups, the topmost member under the point. */
8
+ element: PPTElement;
9
+ /** Ids applied to the selection when this entry is picked (empty when locked). */
10
+ memberIds: string[];
11
+ groupId?: string;
12
+ groupSize?: number;
13
+ locked: boolean;
14
+ }
15
+ /**
16
+ * All layers under a wrapper-space point, top → bottom.
17
+ *
18
+ * Group members collapse into a single entry (picking one selects the whole
19
+ * group, matching canvas click behavior). Hidden elements are skipped; locked
20
+ * elements are listed but marked non-selectable.
21
+ */
22
+ export declare function layerStackAtPoint(elementList: PPTElement[], canvasScale: number, hiddenElementIdList: Iterable<string>, x: number, y: number): LayerStackEntry[];
23
+ /** Index of the next selectable entry below `fromIndex`, wrapping. -1 when none. */
24
+ export declare function nextSelectableLayer(entries: LayerStackEntry[], fromIndex: number): number;
@@ -11,11 +11,11 @@
11
11
  * `.viewport-wrapper` (already sized to the *visual* slide). Position
12
12
  * here is slide × canvasScale.
13
13
  *
14
- * Never use CSS `translate` on the painted box. Auto-size text measures
15
- * and rasterizes differently under a transform than under `left`/`top`,
16
- * so the glyphs shift on pointerup when the transform is removed. Write
17
- * the same `left`/`top` the store will commit — drag and drop are one
18
- * paint path. Scale already does this (`applyLiveSize`).
14
+ * Most elements use `left` / `top` so auto-size text keeps the same
15
+ * measurement and rasterization path during and after the gesture. Complex
16
+ * transparent surfaces can opt into `data-live-translate3d`; those keep
17
+ * their raster on a compositor layer while dragging, then settle to the
18
+ * committed `left` / `top` on pointerup.
19
19
  */
20
20
  export type LiveOffsetPosition = {
21
21
  id: string;
@@ -40,6 +40,7 @@ export type LivePositionCss = {
40
40
  visualTop: string;
41
41
  };
42
42
  export declare const livePositionCss: (left: number, top: number, canvasScale: number) => LivePositionCss;
43
+ export declare const liveTranslate3dCss: (dx: number, dy: number) => string;
43
44
  export declare const applyLivePositionStyles: (nodes: LiveOffsetNodes, left: number, top: number, canvasScale: number) => void;
44
45
  export declare const readLiveMultiOrigin: (canvasScale: number) => {
45
46
  left: number;
@@ -1,9 +1,18 @@
1
1
  import type { Slide } from '../types/slides';
2
2
  export declare const isDataUrl: (src: string) => boolean;
3
+ export declare const isBlobUrl: (src: string) => boolean;
3
4
  export declare const onMediaInterned: (fn: (from: string, to: string) => void) => () => void;
4
5
  /** Data URL and its blob: alias are the same bytes. */
5
6
  export declare const bitmapSrcKeys: (src: string) => string[];
6
7
  export declare const getInternedBlob: (src: string) => Blob | undefined;
8
+ /** Live interned data URL for a blob: src, or the original if it is already persistable. */
9
+ export declare const persistableMediaSrc: (src: string) => string;
10
+ /**
11
+ * Record an object URL created outside the intern layer (e.g. pasted video)
12
+ * so `getInternedBlob` can still inline its bytes during export.
13
+ */
14
+ export declare const registerMediaBlob: (url: string, blob: Blob) => void;
15
+ export declare const rewritePersistableMediaSrcs: <T extends Slide>(slides: T[]) => T[];
7
16
  export declare const startInternSlideMedia: (slide: Slide) => void;
8
17
  export declare const internMediaSrc: (src: string) => Promise<string>;
9
18
  export declare const visitSlideMediaSrcs: (slide: Slide, visit: (src: string) => void) => void;
@@ -22,6 +22,16 @@ export declare const LIST_MARKER_GAP_EM = 0.4;
22
22
  * Kept as a fallback indent (px) when a list item has no padding of its own.
23
23
  */
24
24
  export declare const BULLET_INDENT = 40;
25
+ export interface TextFitRun {
26
+ text: string;
27
+ size: number;
28
+ bold?: boolean;
29
+ italic?: boolean;
30
+ underline?: boolean;
31
+ strikethrough?: boolean;
32
+ color?: string;
33
+ fontFamily?: string;
34
+ }
25
35
  /** A single measurable text block (one paragraph or one list item). */
26
36
  export interface TextFitBlock {
27
37
  /** Plain text of the block (markers stripped). */
@@ -43,12 +53,10 @@ export interface TextFitBlock {
43
53
  * heights match what the browser paints (a 57px body with one 120px word
44
54
  * wraps like 57px and only that one line is 120px tall).
45
55
  */
46
- runs?: Array<{
47
- text: string;
48
- size: number;
49
- bold?: boolean;
50
- italic?: boolean;
51
- }>;
56
+ runs?: TextFitRun[];
57
+ /** Canvas/static-paint metadata. It does not affect fitting math. */
58
+ align?: 'left' | 'center' | 'right' | 'justify';
59
+ listMarker?: string;
52
60
  }
53
61
  export interface MeasureBlocksOptions {
54
62
  /** Box content width in px (insets already removed). */
@@ -0,0 +1,14 @@
1
+ import type { LayerStackEntry } from '../../../utils/layerStack';
2
+ export type ILayerStackPanelProps = {
3
+ /** Canvas-root-relative anchor of the probed point, in px. */
4
+ anchor: {
5
+ x: number;
6
+ y: number;
7
+ };
8
+ entries: LayerStackEntry[];
9
+ activeIndex: number;
10
+ onPick: (index: number) => void;
11
+ onClose: () => void;
12
+ };
13
+ declare const LayerStackPanel: import("react").MemoExoticComponent<(props: ILayerStackPanelProps) => import("react").JSX.Element>;
14
+ export default LayerStackPanel;
@@ -1,3 +1,5 @@
1
+ export declare const OUTLINE_WIDTH_MAX = 20;
2
+ export declare const OUTLINE_RADIUS_MAX = 100;
1
3
  export type IElementOutlineProps = {
2
4
  fixed?: boolean;
3
5
  };
@@ -0,0 +1,11 @@
1
+ import type { Slide } from '../../../types/slides';
2
+ export type ICanvasSlideThumbProps = {
3
+ slide: Slide;
4
+ width: number;
5
+ };
6
+ /**
7
+ * A final-DPR Canvas2D projection of Slide JSON. Existing pixels remain in the
8
+ * backing store while an edit is debounced or an async asset resolves.
9
+ */
10
+ declare const CanvasSlideThumb: import("react").MemoExoticComponent<({ slide, width }: ICanvasSlideThumbProps) => import("react").JSX.Element>;
11
+ export default CanvasSlideThumb;
@@ -7,15 +7,10 @@ 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). */
10
+ /** @deprecated Canvas thumbnails no longer use snapshot capture. */
11
11
  snapshot?: boolean;
12
12
  };
13
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
- */
14
+ /** Model-driven slide thumbnail painted directly at the final device DPR. */
20
15
  declare const ThumbnailSlide: import("react").MemoExoticComponent<(props: IThumbnailSlideProps) => import("react").JSX.Element>;
21
16
  export default ThumbnailSlide;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fika-editor",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
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",
@@ -44,6 +44,9 @@
44
44
  ],
45
45
  "scripts": {
46
46
  "dev": "rsbuild dev",
47
+ "dx": "1dxway start",
48
+ "dx:install": "bunx 1dxway",
49
+ "dx:start": "1dxway start",
47
50
  "doctor": "react-doctor --no-telemetry",
48
51
  "build": "run-p type-check \"build-only {@}\" --",
49
52
  "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",
@@ -55,7 +58,8 @@
55
58
  "preview": "rsbuild preview",
56
59
  "build-only": "rsbuild build",
57
60
  "type-check": "tsc -p tsconfig.app.json --noEmit --pretty false",
58
- "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
61
+ "lint": "oxlint",
62
+ "lint:fix": "oxlint --fix",
59
63
  "test": "node scripts/test.mjs",
60
64
  "i18n": "node scripts/run-i18n.mjs",
61
65
  "i18n:build": "node scripts/run-i18n.mjs --no-watch"
@@ -72,11 +76,11 @@
72
76
  "homepage": "https://github.com/lofcz/fika#readme",
73
77
  "dependencies": {
74
78
  "@chenglou/pretext": "^0.0.8",
75
- "@codemirror/commands": "^6.10.4",
79
+ "@codemirror/commands": "^6.11.0",
76
80
  "@codemirror/lang-json": "^6.0.2",
77
81
  "@codemirror/language": "^6.12.4",
78
82
  "@codemirror/state": "^6.7.1",
79
- "@codemirror/view": "^6.43.8",
83
+ "@codemirror/view": "^6.43.9",
80
84
  "@dnd-kit/core": "^6.3.1",
81
85
  "@dnd-kit/sortable": "^10.0.0",
82
86
  "@dnd-kit/utilities": "^3.2.2",
@@ -84,7 +88,6 @@
84
88
  "@tanstack/react-virtual": "^3.14.9",
85
89
  "@use-gesture/react": "^10.3.1",
86
90
  "@use-gesture/vanilla": "^10.3.1",
87
- "@zumer/snapdom": "^2.24.1",
88
91
  "animate.css": "^4.1.1",
89
92
  "buffer": "^6.0.3",
90
93
  "clipboard": "^2.0.11",
@@ -128,7 +131,7 @@
128
131
  "prosemirror-state": "^1.4.4",
129
132
  "prosemirror-view": "^1.42.2",
130
133
  "rbush": "^4.0.1",
131
- "react-resizable-panels": "^4.12.2",
134
+ "react-resizable-panels": "^4.12.3",
132
135
  "render-tag": "^0.1.29",
133
136
  "shiki": "^4.4.3",
134
137
  "style-to-object": "^2.0.2",
@@ -137,7 +140,7 @@
137
140
  "tippy.js": "^6.3.7",
138
141
  "txml": "^6.0.0",
139
142
  "use-sync-external-store": "^1.6.0",
140
- "wawoff2": "^2.0.1",
143
+ "woff-lib": "^0.0.3",
141
144
  "zustand": "^5.0.15"
142
145
  },
143
146
  "peerDependencies": {
@@ -150,19 +153,20 @@
150
153
  "@rsbuild/plugin-react": "^2.1.0",
151
154
  "@rsbuild/plugin-sass": "^2.0.1",
152
155
  "@rstest/core": "^0.11.8",
153
- "@rushstack/eslint-patch": "^1.16.1",
154
156
  "@types/crypto-js": "^4.2.1",
155
157
  "@types/dompurify": "^3.2.0",
156
158
  "@types/file-saver": "^2.0.7",
157
- "@types/markdown-it": "^14.1.2",
159
+ "@types/markdown-it": "^14.2.0",
158
160
  "@types/node": "^26.2.0",
159
161
  "@types/rbush": "^4.0.0",
160
162
  "@types/react": "^19.2.18",
161
163
  "@types/react-dom": "^19.2.4",
162
164
  "@types/tinycolor2": "^1.4.6",
163
- "eslint": "^10.8.1",
164
- "eslint-plugin-react-hooks": "^7.1.1",
165
+ "1dxway": "^0.1.24",
166
+ "ink": "^7.1.1",
165
167
  "npm-run-all2": "^9.0.3",
168
+ "oxlint": "^1.78.0",
169
+ "oxlint-tsgolint": "^7.0.2001",
166
170
  "playwright": "^1.62.1",
167
171
  "postcss": "^8.5.26",
168
172
  "postcss-selector-parser": "^7.1.5",